prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Pants poetry-based lockfiles fail to include hashes.
  This was detected in a unit test in the Pants repo, but is a wider problem for all versions of Pants that support generating lockfiles using Poetry.
  
  The proximal cause is this announcement from PyPI:
    https://discuss.python.org/t/backwards-incompatible-change-to-pypi-json-api/17154
  
  And the root cause is this Poetry code:
    https://github.com/python-poetry/poetry/blob/bce13c14f73060b3abbb791dea585d8fde26eaef/poetry/repositories/pypi_repository.py#L272-L283
  
  There was a Poetry fix released and backported to the 1.1. branch here:
    https://github.com/python-poetry/poetry/pull/5973
  
  Users can fix with 2 steps:
  1. Update Pants config
  ```toml
  [poetry]
  # N.B.: Works around issue described at https://github.com/pantsbuild/pants/issues/16111
  # Undo once on a Pants with this version or greater as the default.
  version = "poetry==1.1.14"
  ```
  2. Clear Poetry caches with `rm -rf ~/.cache/pypoetry` on Linux and `rm -rf ~/Library/Caches/pypoetry` on Mac.
  
  This issue tracks bumping Pants default to this fixed Poetry version.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/python/pants/backend/python/subsystems/poetry.py`
  Content:
  ```
  1 # Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
  2 # Licensed under the Apache License, Version 2.0 (see LICENSE).
  3 
  4 from __future__ import annotations
  5 
  6 from collections import defaultdict
  7 from dataclasses import dataclass
  8 from textwrap import dedent
  9 from typing import Any, Iterable, Sequence
  10 
  11 import toml
  12 from pkg_resources import Requirement
  13 
  14 from pants.backend.python.subsystems.python_tool_base import PythonToolRequirementsBase
  15 from pants.backend.python.util_rules.interpreter_constraints import InterpreterConstraints
  16 from pants.engine.fs import FileContent
  17 
  18 # ----------------------------------------------------------------------------------------
  19 # Subsystem
  20 # ----------------------------------------------------------------------------------------
  21 
  22 
  23 class PoetrySubsystem(PythonToolRequirementsBase):
  24     options_scope = "poetry"
  25     help = "Used to generate lockfiles for third-party Python dependencies."
  26 
  27     default_version = "poetry==1.1.8"
  28 
  29     register_interpreter_constraints = True
  30     default_interpreter_constraints = ["CPython>=3.7,<4"]
  31 
  32 
  33 # We must monkeypatch Poetry to include `setuptools` and `wheel` in the lockfile. This was fixed
  34 # in Poetry 1.2. See https://github.com/python-poetry/poetry/issues/1584.
  35 # WONTFIX(#12314): only use this custom launcher if using Poetry 1.1..
  36 POETRY_LAUNCHER = FileContent(
  37     "__pants_poetry_launcher.py",
  38     dedent(
  39         """\
  40         from poetry.console import main
  41         from poetry.puzzle.provider import Provider
  42 
  43         Provider.UNSAFE_PACKAGES = set()
  44         main()
  45         """
  46     ).encode(),
  47 )
  48 
  49 
  50 # ----------------------------------------------------------------------------------------
  51 # Parsing
  52 # ----------------------------------------------------------------------------------------
  53 
  54 _HEADER = {
  55     "name": "pants-lockfile-generation",
  56     "version": "0.1.0",
  57     "description": "",
  58     "authors": ["pantsbuild"],
  59 }
  60 
  61 
  62 def create_pyproject_toml(
  63     requirements: Iterable[str], interpreter_constraints: InterpreterConstraints
  64 ) -> str:
  65     return toml.dumps(create_pyproject_toml_as_dict(requirements, interpreter_constraints))
  66 
  67 
  68 def create_pyproject_toml_as_dict(
  69     raw_requirements: Iterable[str], interpreter_constraints: InterpreterConstraints
  70 ) -> dict:
  71     python_constraint = {"python": interpreter_constraints.to_poetry_constraint()}
  72     project_name_to_poetry_deps = defaultdict(list)
  73     for raw_req in raw_requirements:
  74         # WONTFIX(#12314): add error handling.
  75         req = Requirement.parse(raw_req)
  76         poetry_dep = PoetryDependency.from_requirement(req)
  77         project_name_to_poetry_deps[req.project_name].append(poetry_dep)
  78 
  79     deps = {
  80         project_name: PoetryDependency.to_pyproject_toml_metadata(poetry_deps)
  81         for project_name, poetry_deps in project_name_to_poetry_deps.items()
  82     }
  83     return {"tool": {"poetry": {**_HEADER, "dependencies": {**python_constraint, **deps}}}}
  84 
  85 
  86 @dataclass(frozen=True)
  87 class PoetryDependency:
  88     name: str
  89     version: str | None
  90     extras: tuple[str, ...] = ()
  91     markers: str | None = None
  92 
  93     @classmethod
  94     def from_requirement(cls, requirement: Requirement) -> PoetryDependency:
  95         return PoetryDependency(
  96             requirement.project_name,
  97             version=str(requirement.specifier) or None,  # type: ignore[attr-defined]
  98             extras=tuple(sorted(requirement.extras)),
  99             markers=str(requirement.marker) if requirement.marker else None,
  100         )
  101 
  102     @classmethod
  103     def to_pyproject_toml_metadata(
  104         cls, deps: Sequence[PoetryDependency]
  105     ) -> dict[str, Any] | list[dict[str, Any]]:
  106         def convert_dep(dep: PoetryDependency) -> dict[str, Any]:
  107             metadata: dict[str, Any] = {"version": dep.version or "*"}
  108             if dep.extras:
  109                 metadata["extras"] = dep.extras
  110             if dep.markers:
  111                 metadata["markers"] = dep.markers
  112             return metadata
  113 
  114         if not deps:
  115             raise AssertionError("Must have at least one element!")
  116         if len(deps) == 1:
  117             return convert_dep(deps[0])
  118 
  119         entries = []
  120         name = deps[0].name
  121         for dep in deps:
  122             if dep.name != name:
  123                 raise AssertionError(f"All elements must have the same project name. Given: {deps}")
  124             entries.append(convert_dep(dep))
  125         return entries
  126
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/python/pants/backend/python/subsystems/poetry.py b/src/python/pants/backend/python/subsystems/poetry.py
  --- a/src/python/pants/backend/python/subsystems/poetry.py
  +++ b/src/python/pants/backend/python/subsystems/poetry.py
  @@ -24,7 +24,7 @@
       options_scope = "poetry"
       help = "Used to generate lockfiles for third-party Python dependencies."
   
  -    default_version = "poetry==1.1.8"
  +    default_version = "poetry==1.1.14"
   
       register_interpreter_constraints = True
       default_interpreter_constraints = ["CPython>=3.7,<4"]
  
verification_info: {"golden_diff": "diff --git a/src/python/pants/backend/python/subsystems/poetry.py b/src/python/pants/backend/python/subsystems/poetry.py\n--- a/src/python/pants/backend/python/subsystems/poetry.py\n+++ b/src/python/pants/backend/python/subsystems/poetry.py\n@@ -24,7 +24,7 @@\n     options_scope = \"poetry\"\n     help = \"Used to generate lockfiles for third-party Python dependencies.\"\n \n-    default_version = \"poetry==1.1.8\"\n+    default_version = \"poetry==1.1.14\"\n \n     register_interpreter_constraints = True\n     default_interpreter_constraints = [\"CPython>=3.7,<4\"]\n", "issue": "Pants poetry-based lockfiles fail to include hashes.\nThis was detected in a unit test in the Pants repo, but is a wider problem for all versions of Pants that support generating lockfiles using Poetry.\r\n\r\nThe proximal cause is this announcement from PyPI:\r\n  https://discuss.python.org/t/backwards-incompatible-change-to-pypi-json-api/17154\r\n\r\nAnd the root cause is this Poetry code:\r\n  https://github.com/python-poetry/poetry/blob/bce13c14f73060b3abbb791dea585d8fde26eaef/poetry/repositories/pypi_repository.py#L272-L283\r\n\r\nThere was a Poetry fix released and backported to the 1.1. branch here:\r\n  https://github.com/python-poetry/poetry/pull/5973\r\n\r\nUsers can fix with 2 steps:\r\n1. Update Pants config\r\n```toml\r\n[poetry]\r\n# N.B.: Works around issue described at https://github.com/pantsbuild/pants/issues/16111\r\n# Undo once on a Pants with this version or greater as the default.\r\nversion = \"poetry==1.1.14\"\r\n```\r\n2. Clear Poetry caches with `rm -rf ~/.cache/pypoetry` on Linux and `rm -rf ~/Library/Caches/pypoetry` on Mac.\r\n\r\nThis issue tracks bumping Pants default to this fixed Poetry version.\r\n\n", "before_files": [{"content": "# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import annotations\n\nfrom collections import defaultdict\nfrom dataclasses import dataclass\nfrom textwrap import dedent\nfrom typing import Any, Iterable, Sequence\n\nimport toml\nfrom pkg_resources import Requirement\n\nfrom pants.backend.python.subsystems.python_tool_base import PythonToolRequirementsBase\nfrom pants.backend.python.util_rules.interpreter_constraints import InterpreterConstraints\nfrom pants.engine.fs import FileContent\n\n# ----------------------------------------------------------------------------------------\n# Subsystem\n# ----------------------------------------------------------------------------------------\n\n\nclass PoetrySubsystem(PythonToolRequirementsBase):\n    options_scope = \"poetry\"\n    help = \"Used to generate lockfiles for third-party Python dependencies.\"\n\n    default_version = \"poetry==1.1.8\"\n\n    register_interpreter_constraints = True\n    default_interpreter_constraints = [\"CPython>=3.7,<4\"]\n\n\n# We must monkeypatch Poetry to include `setuptools` and `wheel` in the lockfile. This was fixed\n# in Poetry 1.2. See https://github.com/python-poetry/poetry/issues/1584.\n# WONTFIX(#12314): only use this custom launcher if using Poetry 1.1..\nPOETRY_LAUNCHER = FileContent(\n    \"__pants_poetry_launcher.py\",\n    dedent(\n        \"\"\"\\\n        from poetry.console import main\n        from poetry.puzzle.provider import Provider\n\n        Provider.UNSAFE_PACKAGES = set()\n        main()\n        \"\"\"\n    ).encode(),\n)\n\n\n# ----------------------------------------------------------------------------------------\n# Parsing\n# ----------------------------------------------------------------------------------------\n\n_HEADER = {\n    \"name\": \"pants-lockfile-generation\",\n    \"version\": \"0.1.0\",\n    \"description\": \"\",\n    \"authors\": [\"pantsbuild\"],\n}\n\n\ndef create_pyproject_toml(\n    requirements: Iterable[str], interpreter_constraints: InterpreterConstraints\n) -> str:\n    return toml.dumps(create_pyproject_toml_as_dict(requirements, interpreter_constraints))\n\n\ndef create_pyproject_toml_as_dict(\n    raw_requirements: Iterable[str], interpreter_constraints: InterpreterConstraints\n) -> dict:\n    python_constraint = {\"python\": interpreter_constraints.to_poetry_constraint()}\n    project_name_to_poetry_deps = defaultdict(list)\n    for raw_req in raw_requirements:\n        # WONTFIX(#12314): add error handling.\n        req = Requirement.parse(raw_req)\n        poetry_dep = PoetryDependency.from_requirement(req)\n        project_name_to_poetry_deps[req.project_name].append(poetry_dep)\n\n    deps = {\n        project_name: PoetryDependency.to_pyproject_toml_metadata(poetry_deps)\n        for project_name, poetry_deps in project_name_to_poetry_deps.items()\n    }\n    return {\"tool\": {\"poetry\": {**_HEADER, \"dependencies\": {**python_constraint, **deps}}}}\n\n\n@dataclass(frozen=True)\nclass PoetryDependency:\n    name: str\n    version: str | None\n    extras: tuple[str, ...] = ()\n    markers: str | None = None\n\n    @classmethod\n    def from_requirement(cls, requirement: Requirement) -> PoetryDependency:\n        return PoetryDependency(\n            requirement.project_name,\n            version=str(requirement.specifier) or None,  # type: ignore[attr-defined]\n            extras=tuple(sorted(requirement.extras)),\n            markers=str(requirement.marker) if requirement.marker else None,\n        )\n\n    @classmethod\n    def to_pyproject_toml_metadata(\n        cls, deps: Sequence[PoetryDependency]\n    ) -> dict[str, Any] | list[dict[str, Any]]:\n        def convert_dep(dep: PoetryDependency) -> dict[str, Any]:\n            metadata: dict[str, Any] = {\"version\": dep.version or \"*\"}\n            if dep.extras:\n                metadata[\"extras\"] = dep.extras\n            if dep.markers:\n                metadata[\"markers\"] = dep.markers\n            return metadata\n\n        if not deps:\n            raise AssertionError(\"Must have at least one element!\")\n        if len(deps) == 1:\n            return convert_dep(deps[0])\n\n        entries = []\n        name = deps[0].name\n        for dep in deps:\n            if dep.name != name:\n                raise AssertionError(f\"All elements must have the same project name. Given: {deps}\")\n            entries.append(convert_dep(dep))\n        return entries\n", "path": "src/python/pants/backend/python/subsystems/poetry.py"}], "after_files": [{"content": "# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import annotations\n\nfrom collections import defaultdict\nfrom dataclasses import dataclass\nfrom textwrap import dedent\nfrom typing import Any, Iterable, Sequence\n\nimport toml\nfrom pkg_resources import Requirement\n\nfrom pants.backend.python.subsystems.python_tool_base import PythonToolRequirementsBase\nfrom pants.backend.python.util_rules.interpreter_constraints import InterpreterConstraints\nfrom pants.engine.fs import FileContent\n\n# ----------------------------------------------------------------------------------------\n# Subsystem\n# ----------------------------------------------------------------------------------------\n\n\nclass PoetrySubsystem(PythonToolRequirementsBase):\n    options_scope = \"poetry\"\n    help = \"Used to generate lockfiles for third-party Python dependencies.\"\n\n    default_version = \"poetry==1.1.14\"\n\n    register_interpreter_constraints = True\n    default_interpreter_constraints = [\"CPython>=3.7,<4\"]\n\n\n# We must monkeypatch Poetry to include `setuptools` and `wheel` in the lockfile. This was fixed\n# in Poetry 1.2. See https://github.com/python-poetry/poetry/issues/1584.\n# WONTFIX(#12314): only use this custom launcher if using Poetry 1.1..\nPOETRY_LAUNCHER = FileContent(\n    \"__pants_poetry_launcher.py\",\n    dedent(\n        \"\"\"\\\n        from poetry.console import main\n        from poetry.puzzle.provider import Provider\n\n        Provider.UNSAFE_PACKAGES = set()\n        main()\n        \"\"\"\n    ).encode(),\n)\n\n\n# ----------------------------------------------------------------------------------------\n# Parsing\n# ----------------------------------------------------------------------------------------\n\n_HEADER = {\n    \"name\": \"pants-lockfile-generation\",\n    \"version\": \"0.1.0\",\n    \"description\": \"\",\n    \"authors\": [\"pantsbuild\"],\n}\n\n\ndef create_pyproject_toml(\n    requirements: Iterable[str], interpreter_constraints: InterpreterConstraints\n) -> str:\n    return toml.dumps(create_pyproject_toml_as_dict(requirements, interpreter_constraints))\n\n\ndef create_pyproject_toml_as_dict(\n    raw_requirements: Iterable[str], interpreter_constraints: InterpreterConstraints\n) -> dict:\n    python_constraint = {\"python\": interpreter_constraints.to_poetry_constraint()}\n    project_name_to_poetry_deps = defaultdict(list)\n    for raw_req in raw_requirements:\n        # WONTFIX(#12314): add error handling.\n        req = Requirement.parse(raw_req)\n        poetry_dep = PoetryDependency.from_requirement(req)\n        project_name_to_poetry_deps[req.project_name].append(poetry_dep)\n\n    deps = {\n        project_name: PoetryDependency.to_pyproject_toml_metadata(poetry_deps)\n        for project_name, poetry_deps in project_name_to_poetry_deps.items()\n    }\n    return {\"tool\": {\"poetry\": {**_HEADER, \"dependencies\": {**python_constraint, **deps}}}}\n\n\n@dataclass(frozen=True)\nclass PoetryDependency:\n    name: str\n    version: str | None\n    extras: tuple[str, ...] = ()\n    markers: str | None = None\n\n    @classmethod\n    def from_requirement(cls, requirement: Requirement) -> PoetryDependency:\n        return PoetryDependency(\n            requirement.project_name,\n            version=str(requirement.specifier) or None,  # type: ignore[attr-defined]\n            extras=tuple(sorted(requirement.extras)),\n            markers=str(requirement.marker) if requirement.marker else None,\n        )\n\n    @classmethod\n    def to_pyproject_toml_metadata(\n        cls, deps: Sequence[PoetryDependency]\n    ) -> dict[str, Any] | list[dict[str, Any]]:\n        def convert_dep(dep: PoetryDependency) -> dict[str, Any]:\n            metadata: dict[str, Any] = {\"version\": dep.version or \"*\"}\n            if dep.extras:\n                metadata[\"extras\"] = dep.extras\n            if dep.markers:\n                metadata[\"markers\"] = dep.markers\n            return metadata\n\n        if not deps:\n            raise AssertionError(\"Must have at least one element!\")\n        if len(deps) == 1:\n            return convert_dep(deps[0])\n\n        entries = []\n        name = deps[0].name\n        for dep in deps:\n            if dep.name != name:\n                raise AssertionError(f\"All elements must have the same project name. Given: {deps}\")\n            entries.append(convert_dep(dep))\n        return entries\n", "path": "src/python/pants/backend/python/subsystems/poetry.py"}]}