Repository: pdm-project/pdm (python)

Issue:
`KeyError` when running `pdm install`
- [x] I have searched the issue tracker and believe that this is not a duplicate.

**Make sure you run commands with `-v` flag before pasting the output.**

## Steps to reproduce

```
$ mkdir bug; cd bug
$ cat >pyproject.toml
[project]
name = "amaranth-template-fpga"
version = "0.0.0"
description = "Template for a generic FPGA project using Amaranth"

requires-python = "~=3.8"
dependencies = [
    "amaranth[builtin-yosys] @ git+https://github.com/amaranth-lang/amaranth",
    "amaranth-boards @ git+https://github.com/amaranth-lang/amaranth-boards",
    "yowasp-yosys",
    "yowasp-nextpnr-ice40",
    "yowasp-nextpnr-ecp5",
]

[tool.pdm.scripts]
_.env_file = ".env.toolchain"
build_icestick = {call = "amaranth_template_fpga:build_icestick()" }
^D
$ pdm install -v
WARNING: The following problems are found in your project:
  project-config: python.path config needs to be moved to .pdm-python and .pdm.toml needs to be renamed to pdm.toml
Run pdm fix to fix all or pdm fix <name> to fix individual problem.
Lock file does not exist
Updating the lock file...
STATUS: Resolving dependencies
pdm.termui: ======== Start resolving requirements ========
pdm.termui:   amaranth[builtin-yosys] @ git+https://github.com/amaranth-lang/amaranth
pdm.termui:   amaranth-boards @ git+https://github.com/amaranth-lang/amaranth-boards
pdm.termui:   yowasp-yosys
pdm.termui:   yowasp-nextpnr-ice40
pdm.termui:   yowasp-nextpnr-ecp5
pdm.termui:   python>=3.8,<4.0
pdm.termui:   Adding requirement amaranth[builtin-yosys] @ git+https://github.com/amaranth-lang/amaranth
pdm.termui:   Adding requirement amaranth-boards @ git+https://github.com/amaranth-lang/amaranth-boards
pdm.termui:   Adding requirement yowasp-yosys
pdm.termui:   Adding requirement yowasp-nextpnr-ice40
pdm.termui:   Adding requirement yowasp-nextpnr-ecp5
pdm.termui:   Adding requirement python>=3.8,<4.0
pdm.termui: ======== Starting round 0 ========
unearth.vcs.git: Cloning https://github.com/amaranth-lang/amaranth to /tmp/pdm-build-v4iftzzx
unearth.vcs.git: Resolved https://github.com/amaranth-lang/amaranth to commit 7a9dbc8c118ffc70142ebcba7ca1cc55e36d88c9
pdm.termui: Running PEP 517 backend to get metadata for <Link git+https://github.com/amaranth-lang/amaranth (from None)>
pdm.termui: Preparing isolated env for PEP 517 build...
pdm.termui: ======== Start resolving requirements ========
pdm.termui:   setuptools-scm[toml]>=6.2
pdm.termui:   setuptools>=67.0
pdm.termui:   wheel
pdm.termui:   python>=3.11.2,<3.11.3
pdm.termui:   Adding requirement setuptools-scm[toml]>=6.2
pdm.termui:   Adding requirement setuptools>=67.0
pdm.termui:   Adding requirement wheel
pdm.termui:   Adding requirement python>=3.11.2,<3.11.3
pdm.termui: ======== Starting round 0 ========
pdm.termui: Pinning: python None
pdm.termui: ======== Ending round 0 ========
pdm.termui: ======== Starting round 1 ========
pdm.termui: Pinning: setuptools 68.0.0
pdm.termui: ======== Ending round 1 ========
pdm.termui: ======== Starting round 2 ========
pdm.termui:   Adding requirement setuptools>=42(from setuptools-scm 7.1.0)
pdm.termui:   Adding requirement setuptools-scm==7.1.0(from setuptools-scm 7.1.0)
pdm.termui: Pinning: setuptools-scm 7.1.0
pdm.termui: ======== Ending round 2 ========
pdm.termui: ======== Starting round 3 ========
pdm.termui: Pinning: wheel 0.40.0
pdm.termui: ======== Ending round 3 ========
pdm.termui: ======== Starting round 4 ========
pdm.termui:   Adding requirement packaging>=20.0(from setuptools-scm 7.1.0)
pdm.termui:   Adding requirement setuptools(from setuptools-scm 7.1.0)
pdm.termui:   Adding requirement typing-extensions(from setuptools-scm 7.1.0)
pdm.termui: Pinning: setuptools-scm 7.1.0
pdm.termui: ======== Ending round 4 ========
pdm.termui: ======== Starting round 5 ========
pdm.termui: Pinning: packaging 23.1
pdm.termui: ======== Ending round 5 ========
pdm.termui: ======== Starting round 6 ========
pdm.termui: Pinning: typing-extensions 4.7.1
pdm.termui: ======== Ending round 6 ========
pdm.termui: ======== Starting round 7 ========
pdm.termui: ======== Resolution Result ========
pdm.termui: Stable pins:
pdm.termui:                 python None
pdm.termui:             setuptools 68.0.0
pdm.termui:   setuptools-scm[toml] 7.1.0
pdm.termui:                  wheel 0.40.0
pdm.termui:         setuptools-scm 7.1.0
pdm.termui:              packaging 23.1
pdm.termui:      typing-extensions 4.7.1
pdm.termui: Installing packaging@23.1...
unearth.preparer: Using cached <Link https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl (from https://pypi.org/simple/packaging/)>
pdm.termui: Installing setuptools@68.0.0...
unearth.preparer: Using cached <Link https://files.pythonhosted.org/packages/c7/42/be1c7bbdd83e1bfb160c94b9cafd8e25efc7400346cf7ccdbdb452c467fa/setuptools-68.0.0-py3-none-any.whl (from https://pypi.org/simple/setuptools/)>
pdm.termui: Installing setuptools-scm@7.1.0...
unearth.preparer: Using cached <Link https://files.pythonhosted.org/packages/1d/66/8f42c941be949ef2b22fe905d850c794e7c170a526023612aad5f3a121ad/setuptools_scm-7.1.0-py3-none-any.whl (from https://pypi.org/simple/setuptools-scm/)>
pdm.termui: Installing typing-extensions@4.7.1...
unearth.preparer: Using cached <Link https://files.pythonhosted.org/packages/ec/6b/63cc3df74987c36fe26157ee12e09e8f9db4de771e0f3404263117e75b95/typing_extensions-4.7.1-py3-none-any.whl (from https://pypi.org/simple/typing-extensions/)>
pdm.termui: Installing wheel@0.40.0...
unearth.preparer: Using cached <Link https://files.pythonhosted.org/packages/61/86/cc8d1ff2ca31a312a25a708c891cf9facbad4eae493b3872638db6785eb5/wheel-0.40.0-py3-none-any.whl (from https://pypi.org/simple/wheel/)>
pdm.termui: Synchronization complete.
pdm.termui: /tmp/pdm-build-env-5u62rj03-shared/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py:66: _BetaConfiguration: Support for `[tool.setuptools]` in `pyproject.toml` is still *beta*.
pdm.termui:   config = read_configuration(filepath, True, ignore_option_errors, dist)
pdm.termui: running egg_info
pdm.termui: creating amaranth.egg-info
pdm.termui: writing amaranth.egg-info/PKG-INFO
pdm.termui: writing dependency_links to amaranth.egg-info/dependency_links.txt
pdm.termui: writing entry points to amaranth.egg-info/entry_points.txt
pdm.termui: writing requirements to amaranth.egg-info/requires.txt
pdm.termui: writing top-level names to amaranth.egg-info/top_level.txt
pdm.termui: writing manifest file 'amaranth.egg-info/SOURCES.txt'
pdm.termui: adding license file 'LICENSE.txt'
pdm.termui: writing manifest file 'amaranth.egg-info/SOURCES.txt'
pdm.termui: /tmp/pdm-build-env-5u62rj03-shared/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py:66: _BetaConfiguration: Support for `[tool.setuptools]` in `pyproject.toml` is still *beta*.
pdm.termui:   config = read_configuration(filepath, True, ignore_option_errors, dist)
pdm.termui: running dist_info
pdm.termui: creating /tmp/pdm-meta-2a1bfgqp/amaranth.egg-info
pdm.termui: writing /tmp/pdm-meta-2a1bfgqp/amaranth.egg-info/PKG-INFO
pdm.termui: writing dependency_links to /tmp/pdm-meta-2a1bfgqp/amaranth.egg-info/dependency_links.txt
pdm.termui: writing entry points to /tmp/pdm-meta-2a1bfgqp/amaranth.egg-info/entry_points.txt
pdm.termui: writing requirements to /tmp/pdm-meta-2a1bfgqp/amaranth.egg-info/requires.txt
pdm.termui: writing top-level names to /tmp/pdm-meta-2a1bfgqp/amaranth.egg-info/top_level.txt
pdm.termui: writing manifest file '/tmp/pdm-meta-2a1bfgqp/amaranth.egg-info/SOURCES.txt'
pdm.termui: adding license file 'LICENSE.txt'
pdm.termui: writing manifest file '/tmp/pdm-meta-2a1bfgqp/amaranth.egg-info/SOURCES.txt'
pdm.termui: creating '/tmp/pdm-meta-2a1bfgqp/amaranth-0.4.dev149+g7a9dbc8.dist-info'
unearth.vcs.git: Cloning https://github.com/amaranth-lang/amaranth-boards to /tmp/pdm-build-1lq3pgpr
unearth.vcs.git: Resolved https://github.com/amaranth-lang/amaranth-boards to commit 510c28e3799aeca1cbf72ba26771d0951f98412e
pdm.termui: Running PEP 517 backend to get metadata for <Link git+https://github.com/amaranth-lang/amaranth-boards (from None)>
pdm.termui: Preparing isolated env for PEP 517 build...
pdm.termui: ======== Start resolving requirements ========
pdm.termui:   setuptools-scm[toml]>=6.2
pdm.termui:   setuptools~=67.0
pdm.termui:   wheel
pdm.termui:   python>=3.11.2,<3.11.3
pdm.termui:   Adding requirement setuptools-scm[toml]>=6.2
pdm.termui:   Adding requirement setuptools~=67.0
pdm.termui:   Adding requirement wheel
pdm.termui:   Adding requirement python>=3.11.2,<3.11.3
pdm.termui: ======== Starting round 0 ========
pdm.termui: Pinning: python None
pdm.termui: ======== Ending round 0 ========
pdm.termui: ======== Starting round 1 ========
pdm.termui: Pinning: setuptools 67.8.0
pdm.termui: ======== Ending round 1 ========
pdm.termui: ======== Starting round 2 ========
pdm.termui:   Adding requirement setuptools>=42(from setuptools-scm 7.1.0)
pdm.termui:   Adding requirement setuptools-scm==7.1.0(from setuptools-scm 7.1.0)
pdm.termui: Pinning: setuptools-scm 7.1.0
pdm.termui: ======== Ending round 2 ========
pdm.termui: ======== Starting round 3 ========
pdm.termui: Pinning: wheel 0.40.0
pdm.termui: ======== Ending round 3 ========
pdm.termui: ======== Starting round 4 ========
pdm.termui:   Adding requirement packaging>=20.0(from setuptools-scm 7.1.0)
pdm.termui:   Adding requirement setuptools(from setuptools-scm 7.1.0)
pdm.termui:   Adding requirement typing-extensions(from setuptools-scm 7.1.0)
pdm.termui: Pinning: setuptools-scm 7.1.0
pdm.termui: ======== Ending round 4 ========
pdm.termui: ======== Starting round 5 ========
pdm.termui: Pinning: packaging 23.1
pdm.termui: ======== Ending round 5 ========
pdm.termui: ======== Starting round 6 ========
pdm.termui: Pinning: typing-extensions 4.7.1
pdm.termui: ======== Ending round 6 ========
pdm.termui: ======== Starting round 7 ========
pdm.termui: ======== Resolution Result ========
pdm.termui: Stable pins:
pdm.termui:                 python None
pdm.termui:             setuptools 67.8.0
pdm.termui:   setuptools-scm[toml] 7.1.0
pdm.termui:                  wheel 0.40.0
pdm.termui:         setuptools-scm 7.1.0
pdm.termui:              packaging 23.1
pdm.termui:      typing-extensions 4.7.1
pdm.termui: Installing packaging@23.1...
unearth.preparer: Using cached <Link https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl (from https://pypi.org/simple/packaging/)>
pdm.termui: Installing setuptools@67.8.0...
unearth.preparer: Using cached <Link https://files.pythonhosted.org/packages/f5/2c/074ab1c5be9c7d523d8d6d69d1f46f450fe7f11713147dc9e779aa4ca4ea/setuptools-67.8.0-py3-none-any.whl (from https://pypi.org/simple/setuptools/)>
pdm.termui: Installing setuptools-scm@7.1.0...
unearth.preparer: Using cached <Link https://files.pythonhosted.org/packages/1d/66/8f42c941be949ef2b22fe905d850c794e7c170a526023612aad5f3a121ad/setuptools_scm-7.1.0-py3-none-any.whl (from https://pypi.org/simple/setuptools-scm/)>
pdm.termui: Installing typing-extensions@4.7.1...
unearth.preparer: Using cached <Link https://files.pythonhosted.org/packages/ec/6b/63cc3df74987c36fe26157ee12e09e8f9db4de771e0f3404263117e75b95/typing_extensions-4.7.1-py3-none-any.whl (from https://pypi.org/simple/typing-extensions/)>
pdm.termui: Installing wheel@0.40.0...
unearth.preparer: Using cached <Link https://files.pythonhosted.org/packages/61/86/cc8d1ff2ca31a312a25a708c891cf9facbad4eae493b3872638db6785eb5/wheel-0.40.0-py3-none-any.whl (from https://pypi.org/simple/wheel/)>
pdm.termui: Synchronization complete.
pdm.termui: /tmp/pdm-build-env-0enoayiv-shared/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py:66: _BetaConfiguration: Support for `[tool.setuptools]` in `pyproject.toml` is still *beta*.
pdm.termui:   config = read_configuration(filepath, True, ignore_option_errors, dist)
pdm.termui: running egg_info
pdm.termui: creating amaranth_boards.egg-info
pdm.termui: writing amaranth_boards.egg-info/PKG-INFO
pdm.termui: writing dependency_links to amaranth_boards.egg-info/dependency_links.txt
pdm.termui: writing requirements to amaranth_boards.egg-info/requires.txt
pdm.termui: writing top-level names to amaranth_boards.egg-info/top_level.txt
pdm.termui: writing manifest file 'amaranth_boards.egg-info/SOURCES.txt'
pdm.termui: adding license file 'LICENSE.txt'
pdm.termui: writing manifest file 'amaranth_boards.egg-info/SOURCES.txt'
pdm.termui: /tmp/pdm-build-env-0enoayiv-shared/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py:66: _BetaConfiguration: Support for `[tool.setuptools]` in `pyproject.toml` is still *beta*.
pdm.termui:   config = read_configuration(filepath, True, ignore_option_errors, dist)
pdm.termui: running dist_info
pdm.termui: creating /tmp/pdm-meta-9gul_f0m/amaranth_boards.egg-info
pdm.termui: writing /tmp/pdm-meta-9gul_f0m/amaranth_boards.egg-info/PKG-INFO
pdm.termui: writing dependency_links to /tmp/pdm-meta-9gul_f0m/amaranth_boards.egg-info/dependency_links.txt
pdm.termui: writing requirements to /tmp/pdm-meta-9gul_f0m/amaranth_boards.egg-info/requires.txt
pdm.termui: writing top-level names to /tmp/pdm-meta-9gul_f0m/amaranth_boards.egg-info/top_level.txt
pdm.termui: writing manifest file '/tmp/pdm-meta-9gul_f0m/amaranth_boards.egg-info/SOURCES.txt'
pdm.termui: adding license file 'LICENSE.txt'
pdm.termui: writing manifest file '/tmp/pdm-meta-9gul_f0m/amaranth_boards.egg-info/SOURCES.txt'
pdm.termui: creating '/tmp/pdm-meta-9gul_f0m/amaranth_boards-0.1.dev229+g510c28e.dist-info'
STATUS: Resolving: new pin python>=3.8,<4.0
pdm.termui: Pinning: python None
pdm.termui: ======== Ending round 0 ========
pdm.termui: ======== Starting round 1 ========
pdm.termui:   Adding requirement amaranth<0.5,>=0.3(from amaranth-boards 0.1.dev229+g510c28e)
STATUS: Resolving: new pin amaranth-boards 0.1.dev229+g510c28e
pdm.termui: Pinning: amaranth-boards 0.1.dev229+g510c28e
pdm.termui: ======== Ending round 1 ========
pdm.termui: ======== Starting round 2 ========
pdm.termui:   Adding requirement amaranth-yosys>=0.10(from amaranth 0.4.dev149+g7a9dbc8)
pdm.termui:   Adding requirement amaranth @ git+https://github.com/amaranth-lang/amaranth(from amaranth 0.4.dev149+g7a9dbc8)
STATUS: Resolving: new pin amaranth 0.4.dev149+g7a9dbc8
pdm.termui: Pinning: amaranth 0.4.dev149+g7a9dbc8
pdm.termui: ======== Ending round 2 ========
pdm.termui: ======== Starting round 3 ========
unearth.vcs.git: Cloning https://github.com/amaranth-lang/amaranth to /tmp/pdm-build-lqiw0i_2
unearth.vcs.git: Resolved https://github.com/amaranth-lang/amaranth to commit 7a9dbc8c118ffc70142ebcba7ca1cc55e36d88c9
pdm.termui: Running PEP 517 backend to get metadata for <Link git+https://github.com/amaranth-lang/amaranth (from None)>
pdm.termui: Preparing isolated env for PEP 517 build...
pdm.termui: ======== Start resolving requirements ========
pdm.termui:   setuptools-scm[toml]>=6.2
pdm.termui:   python>=3.11.2,<3.11.3
pdm.termui:   Adding requirement setuptools-scm[toml]>=6.2
pdm.termui:   Adding requirement python>=3.11.2,<3.11.3
pdm.termui: ======== Starting round 0 ========
pdm.termui: Pinning: python None
pdm.termui: ======== Ending round 0 ========
pdm.termui: ======== Starting round 1 ========
pdm.termui:   Adding requirement setuptools>=42(from setuptools-scm 7.1.0)
pdm.termui:   Adding requirement setuptools-scm==7.1.0(from setuptools-scm 7.1.0)
pdm.termui: Pinning: setuptools-scm 7.1.0
pdm.termui: ======== Ending round 1 ========
pdm.termui: ======== Starting round 2 ========
pdm.termui:   Adding requirement packaging>=20.0(from setuptools-scm 7.1.0)
pdm.termui:   Adding requirement setuptools(from setuptools-scm 7.1.0)
pdm.termui:   Adding requirement typing-extensions(from setuptools-scm 7.1.0)
pdm.termui: Pinning: setuptools-scm 7.1.0
pdm.termui: ======== Ending round 2 ========
pdm.termui: ======== Starting round 3 ========
pdm.termui: Pinning: setuptools 68.0.0
pdm.termui: ======== Ending round 3 ========
pdm.termui: ======== Starting round 4 ========
pdm.termui: Pinning: packaging 23.1
pdm.termui: ======== Ending round 4 ========
pdm.termui: ======== Starting round 5 ========
pdm.termui: Pinning: typing-extensions 4.7.1
pdm.termui: ======== Ending round 5 ========
pdm.termui: ======== Starting round 6 ========
pdm.termui: ======== Resolution Result ========
pdm.termui: Stable pins:
pdm.termui:                 python None
pdm.termui:   setuptools-scm[toml] 7.1.0
pdm.termui:         setuptools-scm 7.1.0
pdm.termui:             setuptools 68.0.0
pdm.termui:              packaging 23.1
pdm.termui:      typing-extensions 4.7.1
pdm.termui: Synchronization complete.
pdm.termui: /tmp/pdm-build-env-5u62rj03-shared/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py:66: _BetaConfiguration: Support for `[tool.setuptools]` in `pyproject.toml` is still *beta*.
pdm.termui:   config = read_configuration(filepath, True, ignore_option_errors, dist)
pdm.termui: running egg_info
pdm.termui: creating amaranth.egg-info
pdm.termui: writing amaranth.egg-info/PKG-INFO
pdm.termui: writing dependency_links to amaranth.egg-info/dependency_links.txt
pdm.termui: writing entry points to amaranth.egg-info/entry_points.txt
pdm.termui: writing requirements to amaranth.egg-info/requires.txt
pdm.termui: writing top-level names to amaranth.egg-info/top_level.txt
pdm.termui: writing manifest file 'amaranth.egg-info/SOURCES.txt'
pdm.termui: adding license file 'LICENSE.txt'
pdm.termui: writing manifest file 'amaranth.egg-info/SOURCES.txt'
pdm.termui: /tmp/pdm-build-env-5u62rj03-shared/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py:66: _BetaConfiguration: Support for `[tool.setuptools]` in `pyproject.toml` is still *beta*.
pdm.termui:   config = read_configuration(filepath, True, ignore_option_errors, dist)
pdm.termui: running dist_info
pdm.termui: creating /tmp/pdm-meta-4fzyhrz2/amaranth.egg-info
pdm.termui: writing /tmp/pdm-meta-4fzyhrz2/amaranth.egg-info/PKG-INFO
pdm.termui: writing dependency_links to /tmp/pdm-meta-4fzyhrz2/amaranth.egg-info/dependency_links.txt
pdm.termui: writing entry points to /tmp/pdm-meta-4fzyhrz2/amaranth.egg-info/entry_points.txt
pdm.termui: writing requirements to /tmp/pdm-meta-4fzyhrz2/amaranth.egg-info/requires.txt
pdm.termui: writing top-level names to /tmp/pdm-meta-4fzyhrz2/amaranth.egg-info/top_level.txt
pdm.termui: writing manifest file '/tmp/pdm-meta-4fzyhrz2/amaranth.egg-info/SOURCES.txt'
pdm.termui: adding license file 'LICENSE.txt'
pdm.termui: writing manifest file '/tmp/pdm-meta-4fzyhrz2/amaranth.egg-info/SOURCES.txt'
pdm.termui: creating '/tmp/pdm-meta-4fzyhrz2/amaranth-0.4.dev149+g7a9dbc8.dist-info'
pdm.termui:   Adding requirement yowasp-runtime~=1.1(from yowasp-nextpnr-ecp5 0.6.0.0.post440)
STATUS: Resolving: new pin yowasp-nextpnr-ecp5 0.6.0.0.post440
pdm.termui: Pinning: yowasp-nextpnr-ecp5 0.6.0.0.post440
pdm.termui: ======== Ending round 3 ========
pdm.termui: ======== Starting round 4 ========
pdm.termui:   Adding requirement yowasp-runtime~=1.1(from yowasp-nextpnr-ice40 0.6.0.0.post440)
STATUS: Resolving: new pin yowasp-nextpnr-ice40 0.6.0.0.post440
pdm.termui: Pinning: yowasp-nextpnr-ice40 0.6.0.0.post440
pdm.termui: ======== Ending round 4 ========
pdm.termui: ======== Starting round 5 ========
pdm.termui:   Adding requirement yowasp-runtime~=1.12(from yowasp-yosys 0.31.0.0.post550)
pdm.termui:   Adding requirement click(from yowasp-yosys 0.31.0.0.post550)
pdm.termui:   Adding requirement importlib-resources; python_version < "3.9"(from yowasp-yosys 0.31.0.0.post550)
STATUS: Resolving: new pin yowasp-yosys 0.31.0.0.post550
pdm.termui: Pinning: yowasp-yosys 0.31.0.0.post550
pdm.termui: ======== Ending round 5 ========
pdm.termui: ======== Starting round 6 ========
pdm.termui:   Adding requirement pyvcd<0.5,>=0.2.2(from amaranth 0.4.dev149+g7a9dbc8)
pdm.termui:   Adding requirement Jinja2~=3.0(from amaranth 0.4.dev149+g7a9dbc8)
pdm.termui:   Adding requirement importlib-resources; python_version < "3.9"(from amaranth 0.4.dev149+g7a9dbc8)
STATUS: Resolving: new pin amaranth 0.4.dev149+g7a9dbc8
pdm.termui: Pinning: amaranth 0.4.dev149+g7a9dbc8
pdm.termui: ======== Ending round 6 ========
pdm.termui: ======== Starting round 7 ========
pdm.termui:   Adding requirement appdirs~=1.4(from yowasp-runtime 1.28)
pdm.termui:   Adding requirement wasmtime<12,>=1.0(from yowasp-runtime 1.28)
pdm.termui:   Adding requirement importlib-resources; python_version < "3.9"(from yowasp-runtime 1.28)
STATUS: Resolving: new pin yowasp-runtime 1.28
pdm.termui: Pinning: yowasp-runtime 1.28
pdm.termui: ======== Ending round 7 ========
pdm.termui: ======== Starting round 8 ========
pdm.termui:   Adding requirement wasmtime<12,>=1(from amaranth-yosys 0.25.0.0.post74)
pdm.termui:   Adding requirement importlib-resources>=1.4; python_version < "3.9"(from amaranth-yosys 0.25.0.0.post74)
STATUS: Resolving: new pin amaranth-yosys 0.25.0.0.post74
pdm.termui: Pinning: amaranth-yosys 0.25.0.0.post74
pdm.termui: ======== Ending round 8 ========
pdm.termui: ======== Starting round 9 ========
pdm.termui:   Adding requirement zipp>=3.1.0; python_version < "3.10"(from importlib-resources 6.0.0)
STATUS: Resolving: new pin importlib-resources 6.0.0
pdm.termui: Pinning: importlib-resources 6.0.0
pdm.termui: ======== Ending round 9 ========
pdm.termui: ======== Starting round 10 ========
pdm.termui:   Adding requirement colorama; platform_system == "Windows"(from click 8.1.6)
STATUS: Resolving: new pin click 8.1.6
pdm.termui: Pinning: click 8.1.6
pdm.termui: ======== Ending round 10 ========
pdm.termui: ======== Starting round 11 ========
STATUS: Resolving: new pin wasmtime 11.0.0
pdm.termui: Pinning: wasmtime 11.0.0
pdm.termui: ======== Ending round 11 ========
pdm.termui: ======== Starting round 12 ========
STATUS: Resolving: new pin pyvcd 0.4.0
pdm.termui: Pinning: pyvcd 0.4.0
pdm.termui: ======== Ending round 12 ========
pdm.termui: ======== Starting round 13 ========
STATUS: Resolving: new pin appdirs 1.4.4
pdm.termui: Pinning: appdirs 1.4.4
pdm.termui: ======== Ending round 13 ========
pdm.termui: ======== Starting round 14 ========
pdm.termui:   Adding requirement MarkupSafe>=2.0(from Jinja2 3.1.2)
STATUS: Resolving: new pin Jinja2 3.1.2
pdm.termui: Pinning: Jinja2 3.1.2
pdm.termui: ======== Ending round 14 ========
pdm.termui: ======== Starting round 15 ========
STATUS: Resolving: new pin zipp 3.16.2
pdm.termui: Pinning: zipp 3.16.2
pdm.termui: ======== Ending round 15 ========
pdm.termui: ======== Starting round 16 ========
STATUS: Resolving: new pin colorama 0.4.6
pdm.termui: Pinning: colorama 0.4.6
pdm.termui: ======== Ending round 16 ========
pdm.termui: ======== Starting round 17 ========
STATUS: Resolving: new pin MarkupSafe 2.1.3
pdm.termui: Pinning: MarkupSafe 2.1.3
pdm.termui: ======== Ending round 17 ========
pdm.termui: ======== Starting round 18 ========
pdm.termui: ======== Resolution Result ========
pdm.termui: Stable pins:
pdm.termui:                    python None
pdm.termui:           amaranth-boards git+https://github.com/amaranth-lang/amaranth-boards@510c28e3799aeca1cbf72ba26771d0951f98412e
pdm.termui:   amaranth[builtin-yosys] git+https://github.com/amaranth-lang/amaranth@7a9dbc8c118ffc70142ebcba7ca1cc55e36d88c9
pdm.termui:       yowasp-nextpnr-ecp5 0.6.0.0.post440
pdm.termui:      yowasp-nextpnr-ice40 0.6.0.0.post440
pdm.termui:              yowasp-yosys 0.31.0.0.post550
pdm.termui:                  amaranth git+https://github.com/amaranth-lang/amaranth@7a9dbc8c118ffc70142ebcba7ca1cc55e36d88c9
pdm.termui:            yowasp-runtime 1.28
pdm.termui:            amaranth-yosys 0.25.0.0.post74
pdm.termui:       importlib-resources 6.0.0
pdm.termui:                     click 8.1.6
pdm.termui:                  wasmtime 11.0.0
pdm.termui:                     pyvcd 0.4.0
pdm.termui:                   appdirs 1.4.4
pdm.termui:                    jinja2 3.1.2
pdm.termui:                      zipp 3.16.2
pdm.termui:                  colorama 0.4.6
pdm.termui:                markupsafe 2.1.3
STATUS: Fetching hashes for resolved packages...
pdm.termui: Fetching hashes for yowasp-nextpnr-ecp5@0.6.0.0.post440
pdm.termui: Fetching hashes for yowasp-nextpnr-ice40@0.6.0.0.post440
pdm.termui: Fetching hashes for yowasp-runtime@1.28
pdm.termui: Fetching hashes for yowasp-yosys@0.31.0.0.post550
pdm.termui: Fetching hashes for importlib-resources@6.0.0
pdm.termui: Fetching hashes for appdirs@1.4.4
pdm.termui: Fetching hashes for pyvcd@0.4.0
pdm.termui: Fetching hashes for click@8.1.6
pdm.termui: Fetching hashes for wasmtime@11.0.0
pdm.termui: Fetching hashes for amaranth-yosys@0.25.0.0.post74
pdm.termui: Fetching hashes for Jinja2@3.1.2
pdm.termui: Fetching hashes for colorama@0.4.6
pdm.termui: Fetching hashes for zipp@3.16.2
pdm.termui: Fetching hashes for MarkupSafe@2.1.3
🔒 Lock successful
Changes are written to pdm.lock.
STATUS: Resolving packages from lockfile...
Traceback (most recent call last):
  File "/home/whitequark/.local/bin/pdm", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/core.py", line 290, in main
    return Core().main(args or sys.argv[1:])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/core.py", line 208, in main
    raise cast(Exception, err).with_traceback(traceback) from None
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/core.py", line 203, in main
    self.handle(project, options)
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/core.py", line 157, in handle
    command.handle(project, options)
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/cli/commands/install.py", line 95, in handle
    actions.do_sync(
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/cli/actions.py", line 197, in do_sync
    candidates = resolve_candidates_from_lockfile(project, requirements)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/cli/actions.py", line 140, in resolve_candidates_from_lockfile
    mapping, *_ = resolve(
                  ^^^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/resolver/core.py", line 36, in resolve
    result = resolver.resolve(requirements, max_rounds)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/resolvelib/resolvers.py", line 546, in resolve
    state = resolution.resolve(requirements, max_rounds=max_rounds)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/resolvelib/resolvers.py", line 426, in resolve
    name = min(unsatisfied_names, key=self._get_preference)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/resolvelib/resolvers.py", line 203, in _get_preference
    return self._p.get_preference(
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/resolver/providers.py", line 86, in get_preference
    is_backtrack_cause = any(dep.identify() in backtrack_identifiers for dep in self.get_dependencies(candidate))
                                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/resolver/providers.py", line 183, in get_dependencies
    deps, requires_python, _ = self.repository.get_dependencies(candidate)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/models/repositories.py", line 85, in get_dependencies
    requirements, requires_python, summary = getter(candidate)
                                             ^^^^^^^^^^^^^^^^^
  File "/home/whitequark/.local/pipx/venvs/pdm/lib/python3.11/site-packages/pdm/models/repositories.py", line 452, in _get_dependencies_from_lockfile
    return self.candidate_info[self._identify_candidate(candidate)]
           ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
KeyError: ('amaranth', '0.4.dev149+g7a9dbc8', None, False)
```

<!--Describe the minimized example of how to reproduce the bug-->

## Actual behavior

`pdm install` crashes with an opaque error.

## Expected behavior

`pdm install` succeeds or displays a diagnostic.

## Environment Information

```bash
# Paste the output of `pdm info && pdm info --env` below:
PDM version:
  2.8.0
Python Interpreter:
  /home/whitequark/tt/.venv/bin/python (3.11)
Project Root:
  /home/whitequark/tt
Local Packages:

{
  "implementation_name": "cpython",
  "implementation_version": "3.11.2",
  "os_name": "posix",
  "platform_machine": "x86_64",
  "platform_release": "6.1.0-9-amd64",
  "platform_system": "Linux",
  "platform_version": "#1 SMP PREEMPT_DYNAMIC Debian 6.1.27-1 (2023-05-08)",
  "python_full_version": "3.11.2",
  "platform_python_implementation": "CPython",
  "python_version": "3.11",
  "sys_platform": "linux"
}
```


Pull request:
fix: correct the comparison of candidate keys
Fixes #2120

Signed-off-by: Frost Ming <me@frostming.com>

## Pull Request Checklist

- [ ] A news fragment is added in `news/` describing what is new.
- [ ] Test cases added for changed code.

## Describe what you have changed in this PR.


Patch:
diff --git a/news/2120.bugfix.md b/news/2120.bugfix.md
new file mode 100644
index 00000000..7a8e036d
--- /dev/null
+++ b/news/2120.bugfix.md
@@ -0,0 +1,1 @@
+Fix the comparison of the candidate keys in the lockfile.
diff --git a/src/pdm/models/repositories.py b/src/pdm/models/repositories.py
index 7c7071df..59e1f7b7 100644
--- a/src/pdm/models/repositories.py
+++ b/src/pdm/models/repositories.py
@@ -470,10 +470,10 @@ class LockedRepository(BaseRepository):
                 self.candidate_info[can_id] = candidate_info
 
     def _identify_candidate(self, candidate: Candidate) -> CandidateKey:
-        url = getattr(candidate.req, "url", None)
-        if url is not None:
-            url = url_without_fragments(url)
-            url = self.environment.project.backend.expand_line(url)
+        url: str | None = None
+        if candidate.link is not None:
+            url = candidate.link.url_without_fragment
+            url = self.environment.project.backend.expand_line(cast(str, url))
             if url.startswith("file://"):
                 path = posixpath.normpath(url_to_path(url))
                 url = path_to_url(path)
@@ -533,7 +533,6 @@ class LockedRepository(BaseRepository):
             if not requirement.name:
                 # make sure can.identify() won't return a randomly-generated name
                 requirement.name = can.name
-            can.req = requirement
             yield can
 
     def get_hashes(self, candidate: Candidate) -> list[FileHash]:
diff --git a/src/pdm/resolver/providers.py b/src/pdm/resolver/providers.py
index 19fd7fd0..eb94e571 100644
--- a/src/pdm/resolver/providers.py
+++ b/src/pdm/resolver/providers.py
@@ -166,7 +166,10 @@ class BaseProvider(AbstractProvider):
         if not requirement.is_named:
             if candidate.req.is_named:
                 return False
-            return self._compare_file_reqs(requirement, candidate.req)  # type: ignore[arg-type]
+            can_req = candidate.req
+            if requirement.is_vcs and can_req.is_vcs:
+                return can_req.vcs == requirement.vcs and can_req.repo == requirement.repo  # type: ignore[attr-defined]
+            return self._compare_file_reqs(requirement, can_req)  # type: ignore[arg-type]
         version = candidate.version
         this_name = self.repository.environment.project.name
         if version is None or candidate.name == this_name:


Test patch:
diff --git a/tests/fixtures/projects/demo-package/requirements.txt b/tests/fixtures/projects/demo-package/requirements.txt
index 34ef157b..d9409fb4 100644
--- a/tests/fixtures/projects/demo-package/requirements.txt
+++ b/tests/fixtures/projects/demo-package/requirements.txt
@@ -12,10 +12,10 @@ itsdangerous==1.1.0 \
     --hash=sha256:72a1252c0b2cc2bcc351acf2cfe2ec0159d8578c54767d5c2aa67fd869346e55 \
     --hash=sha256:ac4c9f590d59c36b7d2953f97fda415f2461280e5279650aafe1e593f129c4f7 \
     --hash=sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749
-Jinja2==2.11.3 \
+jinja2==2.11.3 \
     --hash=sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419 \
     --hash=sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6
-MarkupSafe==1.1.1 \
+markupsafe==1.1.1 \
     --hash=sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473 \
     --hash=sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161 \
     --hash=sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235 \
@@ -90,7 +90,7 @@ MarkupSafe==1.1.1 \
     --hash=sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7 \
     --hash=sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be \
     --hash=sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621
-Werkzeug==1.0.1 \
+werkzeug==1.0.1 \
     --hash=sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43 \
     --hash=sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c
 --extra-index-url https://test.pypi.org/simple
diff --git a/tests/fixtures/projects/demo-package/requirements_simple.txt b/tests/fixtures/projects/demo-package/requirements_simple.txt
index 0cfe04a7..bd326d31 100644
--- a/tests/fixtures/projects/demo-package/requirements_simple.txt
+++ b/tests/fixtures/projects/demo-package/requirements_simple.txt
@@ -4,7 +4,7 @@
 click==7.1.2
 flask==1.1.4
 itsdangerous==1.1.0
-Jinja2==2.11.3
-MarkupSafe==1.1.1
-Werkzeug==1.0.1
+jinja2==2.11.3
+markupsafe==1.1.1
+werkzeug==1.0.1
 --extra-index-url https://test.pypi.org/simple