prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  License metadata seems to be ignored
  When I made the latest release of `python-dateutil`, it came along with a license change from BSD to Apache / BSD dual licensed.  I updated the `license=` metadata in `setup.py`, but I forgot to update the trove classifiers.
  
  [The page on PyPI](https://pypi.python.org/pypi/python-dateutil/2.7.0) shows the license as "Apache 2.0" as I would expect. [The page on warehouse](https://pypi.org/project/python-dateutil/) shows the license as "BSD License". I'm assuming it's pulling that from the trove classifier? Shouldn't it pull it from the `license` field if that is populated?
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `warehouse/packaging/views.py`
  Content:
  ```
  1 # Licensed under the Apache License, Version 2.0 (the "License");
  2 # you may not use this file except in compliance with the License.
  3 # You may obtain a copy of the License at
  4 #
  5 # http://www.apache.org/licenses/LICENSE-2.0
  6 #
  7 # Unless required by applicable law or agreed to in writing, software
  8 # distributed under the License is distributed on an "AS IS" BASIS,
  9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10 # See the License for the specific language governing permissions and
  11 # limitations under the License.
  12 
  13 from first import first
  14 from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound
  15 from pyramid.view import view_config
  16 from sqlalchemy.orm.exc import NoResultFound
  17 
  18 from warehouse.accounts.models import User
  19 from warehouse.cache.origin import origin_cache
  20 from warehouse.packaging.models import Release, Role
  21 
  22 
  23 @view_config(
  24     route_name="packaging.project",
  25     renderer="packaging/detail.html",
  26     decorator=[
  27         origin_cache(
  28             1 * 24 * 60 * 60,                         # 1 day
  29             stale_while_revalidate=1 * 24 * 60 * 60,  # 1 day
  30             stale_if_error=5 * 24 * 60 * 60,          # 5 days
  31         ),
  32     ],
  33 )
  34 def project_detail(project, request):
  35     if project.name != request.matchdict.get("name", project.name):
  36         return HTTPMovedPermanently(
  37             request.current_route_path(name=project.name),
  38         )
  39 
  40     try:
  41         release = (
  42             request.db.query(Release)
  43                       .filter(Release.project == project)
  44                       .order_by(
  45                           Release.is_prerelease.nullslast(),
  46                           Release._pypi_ordering.desc())
  47                       .limit(1)
  48                       .one()
  49         )
  50     except NoResultFound:
  51         return HTTPNotFound()
  52 
  53     return release_detail(release, request)
  54 
  55 
  56 @view_config(
  57     route_name="packaging.release",
  58     renderer="packaging/detail.html",
  59     decorator=[
  60         origin_cache(
  61             1 * 24 * 60 * 60,                         # 1 day
  62             stale_while_revalidate=1 * 24 * 60 * 60,  # 1 day
  63             stale_if_error=5 * 24 * 60 * 60,          # 5 days
  64         ),
  65     ],
  66 )
  67 def release_detail(release, request):
  68     project = release.project
  69 
  70     # Check if the requested version is equivalent but not exactly the same as
  71     # the release's version. Use `.get` because this view is used by
  72     # `project_detail` and there may not be a version.
  73     #
  74     # This also handles the case where both the version and the project name
  75     # need adjusted, and handles it in a single redirect.
  76     if release.version != request.matchdict.get("version", release.version):
  77         return HTTPMovedPermanently(
  78             request.current_route_path(
  79                 name=project.name,
  80                 version=release.version,
  81             ),
  82         )
  83 
  84     # It's possible that the requested version was correct (or not provided),
  85     # but we still need to adjust the project name.
  86     if project.name != request.matchdict.get("name", project.name):
  87         return HTTPMovedPermanently(
  88             request.current_route_path(name=project.name),
  89         )
  90 
  91     # Get all of the registered versions for this Project, in order of newest
  92     # to oldest.
  93     all_releases = (
  94         request.db.query(Release)
  95                   .filter(Release.project == project)
  96                   .with_entities(
  97                       Release.version,
  98                       Release.is_prerelease,
  99                       Release.created)
  100                   .order_by(Release._pypi_ordering.desc())
  101                   .all()
  102     )
  103 
  104     # Get the latest non-prerelease of this Project, or the latest release if
  105     # all releases are prereleases.
  106     latest_release = first(
  107         all_releases,
  108         key=lambda r: not r.is_prerelease,
  109         default=all_releases[0],
  110     )
  111 
  112     # Get all of the maintainers for this project.
  113     maintainers = [
  114         r.user
  115         for r in (
  116             request.db.query(Role)
  117             .join(User)
  118             .filter(Role.project == project)
  119             .distinct(User.username)
  120             .order_by(User.username)
  121             .all()
  122         )
  123     ]
  124 
  125     # Get the license from the classifiers or metadata, preferring classifiers.
  126     license = None
  127     if release.license:
  128         # Make a best effort when the entire license text is given
  129         # by using the first line only.
  130         license = release.license.split('\n')[0]
  131     license_classifiers = [c.split(" :: ")[-1] for c in release.classifiers
  132                            if c.startswith("License")]
  133     if license_classifiers:
  134         license = ', '.join(license_classifiers)
  135 
  136     return {
  137         "project": project,
  138         "release": release,
  139         "files": release.files.all(),
  140         "latest_release": latest_release,
  141         "all_releases": all_releases,
  142         "maintainers": maintainers,
  143         "license": license,
  144     }
  145 
  146 
  147 @view_config(
  148     route_name="includes.edit-project-button",
  149     renderer="includes/manage-project-button.html",
  150     uses_session=True,
  151     permission="manage",
  152 )
  153 def edit_project_button(project, request):
  154     return {'project': project}
  155
  ```
  --- 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/warehouse/packaging/views.py b/warehouse/packaging/views.py
  --- a/warehouse/packaging/views.py
  +++ b/warehouse/packaging/views.py
  @@ -122,16 +122,21 @@
           )
       ]
   
  -    # Get the license from the classifiers or metadata, preferring classifiers.
  -    license = None
  -    if release.license:
  -        # Make a best effort when the entire license text is given
  -        # by using the first line only.
  -        license = release.license.split('\n')[0]
  -    license_classifiers = [c.split(" :: ")[-1] for c in release.classifiers
  -                           if c.startswith("License")]
  -    if license_classifiers:
  -        license = ', '.join(license_classifiers)
  +    # Get the license from both the `Classifier` and `License` metadata fields
  +    license_classifiers = ', '.join(
  +        c.split(" :: ")[-1]
  +        for c in release.classifiers
  +        if c.startswith("License")
  +    )
  +
  +    # Make a best effort when the entire license text is given by using the
  +    # first line only.
  +    short_license = release.license.split('\n')[0] if release.license else None
  +
  +    if license_classifiers and short_license:
  +        license = f'{license_classifiers} ({short_license})'
  +    else:
  +        license = license_classifiers or short_license or None
   
       return {
           "project": project,
  
verification_info: {"golden_diff": "diff --git a/warehouse/packaging/views.py b/warehouse/packaging/views.py\n--- a/warehouse/packaging/views.py\n+++ b/warehouse/packaging/views.py\n@@ -122,16 +122,21 @@\n         )\n     ]\n \n-    # Get the license from the classifiers or metadata, preferring classifiers.\n-    license = None\n-    if release.license:\n-        # Make a best effort when the entire license text is given\n-        # by using the first line only.\n-        license = release.license.split('\\n')[0]\n-    license_classifiers = [c.split(\" :: \")[-1] for c in release.classifiers\n-                           if c.startswith(\"License\")]\n-    if license_classifiers:\n-        license = ', '.join(license_classifiers)\n+    # Get the license from both the `Classifier` and `License` metadata fields\n+    license_classifiers = ', '.join(\n+        c.split(\" :: \")[-1]\n+        for c in release.classifiers\n+        if c.startswith(\"License\")\n+    )\n+\n+    # Make a best effort when the entire license text is given by using the\n+    # first line only.\n+    short_license = release.license.split('\\n')[0] if release.license else None\n+\n+    if license_classifiers and short_license:\n+        license = f'{license_classifiers} ({short_license})'\n+    else:\n+        license = license_classifiers or short_license or None\n \n     return {\n         \"project\": project,\n", "issue": "License metadata seems to be ignored\nWhen I made the latest release of `python-dateutil`, it came along with a license change from BSD to Apache / BSD dual licensed.  I updated the `license=` metadata in `setup.py`, but I forgot to update the trove classifiers.\r\n\r\n[The page on PyPI](https://pypi.python.org/pypi/python-dateutil/2.7.0) shows the license as \"Apache 2.0\" as I would expect. [The page on warehouse](https://pypi.org/project/python-dateutil/) shows the license as \"BSD License\". I'm assuming it's pulling that from the trove classifier? Shouldn't it pull it from the `license` field if that is populated?\n", "before_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom first import first\nfrom pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\nfrom pyramid.view import view_config\nfrom sqlalchemy.orm.exc import NoResultFound\n\nfrom warehouse.accounts.models import User\nfrom warehouse.cache.origin import origin_cache\nfrom warehouse.packaging.models import Release, Role\n\n\n@view_config(\n    route_name=\"packaging.project\",\n    renderer=\"packaging/detail.html\",\n    decorator=[\n        origin_cache(\n            1 * 24 * 60 * 60,                         # 1 day\n            stale_while_revalidate=1 * 24 * 60 * 60,  # 1 day\n            stale_if_error=5 * 24 * 60 * 60,          # 5 days\n        ),\n    ],\n)\ndef project_detail(project, request):\n    if project.name != request.matchdict.get(\"name\", project.name):\n        return HTTPMovedPermanently(\n            request.current_route_path(name=project.name),\n        )\n\n    try:\n        release = (\n            request.db.query(Release)\n                      .filter(Release.project == project)\n                      .order_by(\n                          Release.is_prerelease.nullslast(),\n                          Release._pypi_ordering.desc())\n                      .limit(1)\n                      .one()\n        )\n    except NoResultFound:\n        return HTTPNotFound()\n\n    return release_detail(release, request)\n\n\n@view_config(\n    route_name=\"packaging.release\",\n    renderer=\"packaging/detail.html\",\n    decorator=[\n        origin_cache(\n            1 * 24 * 60 * 60,                         # 1 day\n            stale_while_revalidate=1 * 24 * 60 * 60,  # 1 day\n            stale_if_error=5 * 24 * 60 * 60,          # 5 days\n        ),\n    ],\n)\ndef release_detail(release, request):\n    project = release.project\n\n    # Check if the requested version is equivalent but not exactly the same as\n    # the release's version. Use `.get` because this view is used by\n    # `project_detail` and there may not be a version.\n    #\n    # This also handles the case where both the version and the project name\n    # need adjusted, and handles it in a single redirect.\n    if release.version != request.matchdict.get(\"version\", release.version):\n        return HTTPMovedPermanently(\n            request.current_route_path(\n                name=project.name,\n                version=release.version,\n            ),\n        )\n\n    # It's possible that the requested version was correct (or not provided),\n    # but we still need to adjust the project name.\n    if project.name != request.matchdict.get(\"name\", project.name):\n        return HTTPMovedPermanently(\n            request.current_route_path(name=project.name),\n        )\n\n    # Get all of the registered versions for this Project, in order of newest\n    # to oldest.\n    all_releases = (\n        request.db.query(Release)\n                  .filter(Release.project == project)\n                  .with_entities(\n                      Release.version,\n                      Release.is_prerelease,\n                      Release.created)\n                  .order_by(Release._pypi_ordering.desc())\n                  .all()\n    )\n\n    # Get the latest non-prerelease of this Project, or the latest release if\n    # all releases are prereleases.\n    latest_release = first(\n        all_releases,\n        key=lambda r: not r.is_prerelease,\n        default=all_releases[0],\n    )\n\n    # Get all of the maintainers for this project.\n    maintainers = [\n        r.user\n        for r in (\n            request.db.query(Role)\n            .join(User)\n            .filter(Role.project == project)\n            .distinct(User.username)\n            .order_by(User.username)\n            .all()\n        )\n    ]\n\n    # Get the license from the classifiers or metadata, preferring classifiers.\n    license = None\n    if release.license:\n        # Make a best effort when the entire license text is given\n        # by using the first line only.\n        license = release.license.split('\\n')[0]\n    license_classifiers = [c.split(\" :: \")[-1] for c in release.classifiers\n                           if c.startswith(\"License\")]\n    if license_classifiers:\n        license = ', '.join(license_classifiers)\n\n    return {\n        \"project\": project,\n        \"release\": release,\n        \"files\": release.files.all(),\n        \"latest_release\": latest_release,\n        \"all_releases\": all_releases,\n        \"maintainers\": maintainers,\n        \"license\": license,\n    }\n\n\n@view_config(\n    route_name=\"includes.edit-project-button\",\n    renderer=\"includes/manage-project-button.html\",\n    uses_session=True,\n    permission=\"manage\",\n)\ndef edit_project_button(project, request):\n    return {'project': project}\n", "path": "warehouse/packaging/views.py"}], "after_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom first import first\nfrom pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\nfrom pyramid.view import view_config\nfrom sqlalchemy.orm.exc import NoResultFound\n\nfrom warehouse.accounts.models import User\nfrom warehouse.cache.origin import origin_cache\nfrom warehouse.packaging.models import Release, Role\n\n\n@view_config(\n    route_name=\"packaging.project\",\n    renderer=\"packaging/detail.html\",\n    decorator=[\n        origin_cache(\n            1 * 24 * 60 * 60,                         # 1 day\n            stale_while_revalidate=1 * 24 * 60 * 60,  # 1 day\n            stale_if_error=5 * 24 * 60 * 60,          # 5 days\n        ),\n    ],\n)\ndef project_detail(project, request):\n    if project.name != request.matchdict.get(\"name\", project.name):\n        return HTTPMovedPermanently(\n            request.current_route_path(name=project.name),\n        )\n\n    try:\n        release = (\n            request.db.query(Release)\n                      .filter(Release.project == project)\n                      .order_by(\n                          Release.is_prerelease.nullslast(),\n                          Release._pypi_ordering.desc())\n                      .limit(1)\n                      .one()\n        )\n    except NoResultFound:\n        return HTTPNotFound()\n\n    return release_detail(release, request)\n\n\n@view_config(\n    route_name=\"packaging.release\",\n    renderer=\"packaging/detail.html\",\n    decorator=[\n        origin_cache(\n            1 * 24 * 60 * 60,                         # 1 day\n            stale_while_revalidate=1 * 24 * 60 * 60,  # 1 day\n            stale_if_error=5 * 24 * 60 * 60,          # 5 days\n        ),\n    ],\n)\ndef release_detail(release, request):\n    project = release.project\n\n    # Check if the requested version is equivalent but not exactly the same as\n    # the release's version. Use `.get` because this view is used by\n    # `project_detail` and there may not be a version.\n    #\n    # This also handles the case where both the version and the project name\n    # need adjusted, and handles it in a single redirect.\n    if release.version != request.matchdict.get(\"version\", release.version):\n        return HTTPMovedPermanently(\n            request.current_route_path(\n                name=project.name,\n                version=release.version,\n            ),\n        )\n\n    # It's possible that the requested version was correct (or not provided),\n    # but we still need to adjust the project name.\n    if project.name != request.matchdict.get(\"name\", project.name):\n        return HTTPMovedPermanently(\n            request.current_route_path(name=project.name),\n        )\n\n    # Get all of the registered versions for this Project, in order of newest\n    # to oldest.\n    all_releases = (\n        request.db.query(Release)\n                  .filter(Release.project == project)\n                  .with_entities(\n                      Release.version,\n                      Release.is_prerelease,\n                      Release.created)\n                  .order_by(Release._pypi_ordering.desc())\n                  .all()\n    )\n\n    # Get the latest non-prerelease of this Project, or the latest release if\n    # all releases are prereleases.\n    latest_release = first(\n        all_releases,\n        key=lambda r: not r.is_prerelease,\n        default=all_releases[0],\n    )\n\n    # Get all of the maintainers for this project.\n    maintainers = [\n        r.user\n        for r in (\n            request.db.query(Role)\n            .join(User)\n            .filter(Role.project == project)\n            .distinct(User.username)\n            .order_by(User.username)\n            .all()\n        )\n    ]\n\n    # Get the license from both the `Classifier` and `License` metadata fields\n    license_classifiers = ', '.join(\n        c.split(\" :: \")[-1]\n        for c in release.classifiers\n        if c.startswith(\"License\")\n    )\n\n    # Make a best effort when the entire license text is given by using the\n    # first line only.\n    short_license = release.license.split('\\n')[0] if release.license else None\n\n    if license_classifiers and short_license:\n        license = f'{license_classifiers} ({short_license})'\n    else:\n        license = license_classifiers or short_license or None\n\n    return {\n        \"project\": project,\n        \"release\": release,\n        \"files\": release.files.all(),\n        \"latest_release\": latest_release,\n        \"all_releases\": all_releases,\n        \"maintainers\": maintainers,\n        \"license\": license,\n    }\n\n\n@view_config(\n    route_name=\"includes.edit-project-button\",\n    renderer=\"includes/manage-project-button.html\",\n    uses_session=True,\n    permission=\"manage\",\n)\ndef edit_project_button(project, request):\n    return {'project': project}\n", "path": "warehouse/packaging/views.py"}]}