We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Reorder trove classifiers on search sidebar
It strikes me that the current ordering is probably not the most useful.

Maybe we reorder to be:
- By Topic
- By Intended Audience
- By Framework
- By Environment
- By License
- By Programming Language
- By Operating System
- By Natural Language
- By Development Status

Thoughts @dstufft ?


--- 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/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 import collections
14 
15 from pyramid.httpexceptions import (
16     HTTPException, HTTPSeeOther, HTTPMovedPermanently, HTTPNotFound,
17     HTTPBadRequest,
18 )
19 from pyramid.view import (
20     notfound_view_config, forbidden_view_config, view_config,
21 )
22 from elasticsearch_dsl import Q
23 from sqlalchemy import func
24 from sqlalchemy.orm import aliased, joinedload
25 
26 from warehouse.accounts import REDIRECT_FIELD_NAME
27 from warehouse.accounts.models import User
28 from warehouse.cache.origin import origin_cache
29 from warehouse.cache.http import cache_control
30 from warehouse.classifiers.models import Classifier
31 from warehouse.packaging.models import Project, Release, File
32 from warehouse.utils.row_counter import RowCount
33 from warehouse.utils.paginate import ElasticsearchPage, paginate_url_factory
34 
35 
36 SEARCH_FIELDS = [
37     "author", "author_email", "description", "download_url", "home_page",
38     "keywords", "license", "maintainer", "maintainer_email", "normalized_name",
39     "platform", "summary",
40 ]
41 SEARCH_BOOSTS = {
42     "normalized_name": 10,
43     "description": 5,
44     "keywords": 5,
45     "summary": 5,
46 }
47 
48 
49 @view_config(context=HTTPException)
50 @notfound_view_config(append_slash=HTTPMovedPermanently)
51 def httpexception_view(exc, request):
52     return exc
53 
54 
55 @forbidden_view_config()
56 def forbidden(exc, request):
57     # If the forbidden error is because the user isn't logged in, then we'll
58     # redirect them to the log in page.
59     if request.authenticated_userid is None:
60         url = request.route_url(
61             "accounts.login",
62             _query={REDIRECT_FIELD_NAME: request.path_qs},
63         )
64         return HTTPSeeOther(url)
65 
66     # If we've reached here, then the user is logged in and they are genuinely
67     # not allowed to access this page.
68     # TODO: Style the forbidden page.
69     return exc
70 
71 
72 @view_config(
73     route_name="robots.txt",
74     renderer="robots.txt",
75     decorator=[
76         cache_control(1 * 24 * 60 * 60),         # 1 day
77         origin_cache(
78             1 * 24 * 60 * 60,                    # 1 day
79             stale_while_revalidate=6 * 60 * 60,  # 6 hours
80             stale_if_error=1 * 24 * 60 * 60,     # 1 day
81         ),
82     ],
83 )
84 def robotstxt(request):
85     request.response.content_type = "text/plain"
86     return {}
87 
88 
89 @view_config(
90     route_name="index",
91     renderer="index.html",
92     decorator=[
93         origin_cache(
94             1 * 60 * 60,                      # 1 hour
95             stale_while_revalidate=10 * 60,   # 10 minutes
96             stale_if_error=1 * 24 * 60 * 60,  # 1 day
97             keys=["all-projects"],
98         ),
99     ]
100 )
101 def index(request):
102     project_names = [
103         r[0] for r in (
104             request.db.query(File.name)
105                    .group_by(File.name)
106                    .order_by(func.sum(File.downloads).desc())
107                    .limit(5)
108                    .all())
109     ]
110     release_a = aliased(
111         Release,
112         request.db.query(Release)
113                   .distinct(Release.name)
114                   .filter(Release.name.in_(project_names))
115                   .order_by(Release.name, Release._pypi_ordering.desc())
116                   .subquery(),
117     )
118     top_projects = (
119         request.db.query(release_a)
120                .options(joinedload(release_a.project))
121                .order_by(func.array_idx(project_names, release_a.name))
122                .all()
123     )
124 
125     latest_releases = (
126         request.db.query(Release)
127                   .options(joinedload(Release.project))
128                   .order_by(Release.created.desc())
129                   .limit(5)
130                   .all()
131     )
132 
133     counts = dict(
134         request.db.query(RowCount.table_name, RowCount.count)
135                   .filter(
136                       RowCount.table_name.in_([
137                           Project.__tablename__,
138                           Release.__tablename__,
139                           File.__tablename__,
140                           User.__tablename__,
141                       ]))
142                   .all()
143     )
144 
145     return {
146         "latest_releases": latest_releases,
147         "top_projects": top_projects,
148         "num_projects": counts.get(Project.__tablename__, 0),
149         "num_releases": counts.get(Release.__tablename__, 0),
150         "num_files": counts.get(File.__tablename__, 0),
151         "num_users": counts.get(User.__tablename__, 0),
152     }
153 
154 
155 @view_config(
156     route_name="search",
157     renderer="search/results.html",
158     decorator=[
159         origin_cache(
160             1 * 60 * 60,                      # 1 hour
161             stale_while_revalidate=10 * 60,   # 10 minutes
162             stale_if_error=1 * 24 * 60 * 60,  # 1 day
163             keys=["all-projects"],
164         )
165     ],
166 )
167 def search(request):
168 
169     q = request.params.get("q", '')
170 
171     if q:
172         should = []
173         for field in SEARCH_FIELDS:
174             kw = {"query": q}
175             if field in SEARCH_BOOSTS:
176                 kw["boost"] = SEARCH_BOOSTS[field]
177             should.append(Q("match", **{field: kw}))
178 
179         # Add a prefix query if ``q`` is longer than one character.
180         if len(q) > 1:
181             should.append(Q('prefix', normalized_name=q))
182 
183         query = request.es.query("dis_max", queries=should)
184         query = query.suggest("name_suggestion", q, term={"field": "name"})
185     else:
186         query = request.es.query()
187 
188     if request.params.get("o"):
189         query = query.sort(request.params["o"])
190 
191     if request.params.getall("c"):
192         query = query.filter("terms", classifiers=request.params.getall("c"))
193 
194     try:
195         page_num = int(request.params.get("page", 1))
196     except ValueError:
197         raise HTTPBadRequest("'page' must be an integer.")
198 
199     page = ElasticsearchPage(
200         query,
201         page=page_num,
202         url_maker=paginate_url_factory(request),
203     )
204 
205     if page.page_count and page_num > page.page_count:
206         return HTTPNotFound()
207 
208     available_filters = collections.defaultdict(list)
209 
210     for cls in request.db.query(Classifier).order_by(Classifier.classifier):
211         first, *_ = cls.classifier.split(' :: ')
212         available_filters[first].append(cls.classifier)
213 
214     return {
215         "page": page,
216         "term": q,
217         "order": request.params.get("o", ''),
218         "available_filters": sorted(available_filters.items()),
219         "applied_filters": request.params.getall("c"),
220     }
221 
222 
223 @view_config(
224     route_name="includes.current-user-indicator",
225     renderer="includes/current-user-indicator.html",
226     uses_session=True,
227 )
228 def current_user_indicator(request):
229     return {}
230 
231 
232 @view_config(route_name="health", renderer="string")
233 def health(request):
234     # This will ensure that we can access the database and run queries against
235     # it without doing anything that will take a lock or block other queries.
236     request.db.execute("SELECT 1")
237 
238     # Nothing will actually check this, but it's a little nicer to have
239     # something to return besides an empty body.
240     return "OK"
241
```
--- 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()

```

diff --git a/warehouse/views.py b/warehouse/views.py
--- a/warehouse/views.py
+++ b/warehouse/views.py
@@ -44,6 +44,17 @@
     "keywords": 5,
     "summary": 5,
 }
+SEARCH_FILTER_ORDER = (
+    "Programming Language",
+    "License",
+    "Framework",
+    "Topic",
+    "Intended Audience",
+    "Environment",
+    "Operating System",
+    "Natural Language",
+    "Development Status",
+)
 
 
 @view_config(context=HTTPException)
@@ -211,11 +222,17 @@
         first, *_ = cls.classifier.split(' :: ')
         available_filters[first].append(cls.classifier)
 
+    def filter_key(item):
+        try:
+            return 0, SEARCH_FILTER_ORDER.index(item[0]), item[0]
+        except ValueError:
+            return 1, 0, item[0]
+
     return {
         "page": page,
         "term": q,
         "order": request.params.get("o", ''),
-        "available_filters": sorted(available_filters.items()),
+        "available_filters": sorted(available_filters.items(), key=filter_key),
         "applied_filters": request.params.getall("c"),
     }

{"golden_diff": "diff --git a/warehouse/views.py b/warehouse/views.py\n--- a/warehouse/views.py\n+++ b/warehouse/views.py\n@@ -44,6 +44,17 @@\n     \"keywords\": 5,\n     \"summary\": 5,\n }\n+SEARCH_FILTER_ORDER = (\n+    \"Programming Language\",\n+    \"License\",\n+    \"Framework\",\n+    \"Topic\",\n+    \"Intended Audience\",\n+    \"Environment\",\n+    \"Operating System\",\n+    \"Natural Language\",\n+    \"Development Status\",\n+)\n \n \n @view_config(context=HTTPException)\n@@ -211,11 +222,17 @@\n         first, *_ = cls.classifier.split(' :: ')\n         available_filters[first].append(cls.classifier)\n \n+    def filter_key(item):\n+        try:\n+            return 0, SEARCH_FILTER_ORDER.index(item[0]), item[0]\n+        except ValueError:\n+            return 1, 0, item[0]\n+\n     return {\n         \"page\": page,\n         \"term\": q,\n         \"order\": request.params.get(\"o\", ''),\n-        \"available_filters\": sorted(available_filters.items()),\n+        \"available_filters\": sorted(available_filters.items(), key=filter_key),\n         \"applied_filters\": request.params.getall(\"c\"),\n     }\n", "issue": "Reorder trove classifiers on search sidebar\nIt strikes me that the current ordering is probably not the most useful.\n\nMaybe we reorder to be:\n- By Topic\n- By Intended Audience\n- By Framework\n- By Environment\n- By License\n- By Programming Language\n- By Operating System\n- By Natural Language\n- By Development Status\n\nThoughts @dstufft ?\n\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\nimport collections\n\nfrom pyramid.httpexceptions import (\n    HTTPException, HTTPSeeOther, HTTPMovedPermanently, HTTPNotFound,\n    HTTPBadRequest,\n)\nfrom pyramid.view import (\n    notfound_view_config, forbidden_view_config, view_config,\n)\nfrom elasticsearch_dsl import Q\nfrom sqlalchemy import func\nfrom sqlalchemy.orm import aliased, joinedload\n\nfrom warehouse.accounts import REDIRECT_FIELD_NAME\nfrom warehouse.accounts.models import User\nfrom warehouse.cache.origin import origin_cache\nfrom warehouse.cache.http import cache_control\nfrom warehouse.classifiers.models import Classifier\nfrom warehouse.packaging.models import Project, Release, File\nfrom warehouse.utils.row_counter import RowCount\nfrom warehouse.utils.paginate import ElasticsearchPage, paginate_url_factory\n\n\nSEARCH_FIELDS = [\n    \"author\", \"author_email\", \"description\", \"download_url\", \"home_page\",\n    \"keywords\", \"license\", \"maintainer\", \"maintainer_email\", \"normalized_name\",\n    \"platform\", \"summary\",\n]\nSEARCH_BOOSTS = {\n    \"normalized_name\": 10,\n    \"description\": 5,\n    \"keywords\": 5,\n    \"summary\": 5,\n}\n\n\n@view_config(context=HTTPException)\n@notfound_view_config(append_slash=HTTPMovedPermanently)\ndef httpexception_view(exc, request):\n    return exc\n\n\n@forbidden_view_config()\ndef forbidden(exc, request):\n    # If the forbidden error is because the user isn't logged in, then we'll\n    # redirect them to the log in page.\n    if request.authenticated_userid is None:\n        url = request.route_url(\n            \"accounts.login\",\n            _query={REDIRECT_FIELD_NAME: request.path_qs},\n        )\n        return HTTPSeeOther(url)\n\n    # If we've reached here, then the user is logged in and they are genuinely\n    # not allowed to access this page.\n    # TODO: Style the forbidden page.\n    return exc\n\n\n@view_config(\n    route_name=\"robots.txt\",\n    renderer=\"robots.txt\",\n    decorator=[\n        cache_control(1 * 24 * 60 * 60),         # 1 day\n        origin_cache(\n            1 * 24 * 60 * 60,                    # 1 day\n            stale_while_revalidate=6 * 60 * 60,  # 6 hours\n            stale_if_error=1 * 24 * 60 * 60,     # 1 day\n        ),\n    ],\n)\ndef robotstxt(request):\n    request.response.content_type = \"text/plain\"\n    return {}\n\n\n@view_config(\n    route_name=\"index\",\n    renderer=\"index.html\",\n    decorator=[\n        origin_cache(\n            1 * 60 * 60,                      # 1 hour\n            stale_while_revalidate=10 * 60,   # 10 minutes\n            stale_if_error=1 * 24 * 60 * 60,  # 1 day\n            keys=[\"all-projects\"],\n        ),\n    ]\n)\ndef index(request):\n    project_names = [\n        r[0] for r in (\n            request.db.query(File.name)\n                   .group_by(File.name)\n                   .order_by(func.sum(File.downloads).desc())\n                   .limit(5)\n                   .all())\n    ]\n    release_a = aliased(\n        Release,\n        request.db.query(Release)\n                  .distinct(Release.name)\n                  .filter(Release.name.in_(project_names))\n                  .order_by(Release.name, Release._pypi_ordering.desc())\n                  .subquery(),\n    )\n    top_projects = (\n        request.db.query(release_a)\n               .options(joinedload(release_a.project))\n               .order_by(func.array_idx(project_names, release_a.name))\n               .all()\n    )\n\n    latest_releases = (\n        request.db.query(Release)\n                  .options(joinedload(Release.project))\n                  .order_by(Release.created.desc())\n                  .limit(5)\n                  .all()\n    )\n\n    counts = dict(\n        request.db.query(RowCount.table_name, RowCount.count)\n                  .filter(\n                      RowCount.table_name.in_([\n                          Project.__tablename__,\n                          Release.__tablename__,\n                          File.__tablename__,\n                          User.__tablename__,\n                      ]))\n                  .all()\n    )\n\n    return {\n        \"latest_releases\": latest_releases,\n        \"top_projects\": top_projects,\n        \"num_projects\": counts.get(Project.__tablename__, 0),\n        \"num_releases\": counts.get(Release.__tablename__, 0),\n        \"num_files\": counts.get(File.__tablename__, 0),\n        \"num_users\": counts.get(User.__tablename__, 0),\n    }\n\n\n@view_config(\n    route_name=\"search\",\n    renderer=\"search/results.html\",\n    decorator=[\n        origin_cache(\n            1 * 60 * 60,                      # 1 hour\n            stale_while_revalidate=10 * 60,   # 10 minutes\n            stale_if_error=1 * 24 * 60 * 60,  # 1 day\n            keys=[\"all-projects\"],\n        )\n    ],\n)\ndef search(request):\n\n    q = request.params.get(\"q\", '')\n\n    if q:\n        should = []\n        for field in SEARCH_FIELDS:\n            kw = {\"query\": q}\n            if field in SEARCH_BOOSTS:\n                kw[\"boost\"] = SEARCH_BOOSTS[field]\n            should.append(Q(\"match\", **{field: kw}))\n\n        # Add a prefix query if ``q`` is longer than one character.\n        if len(q) > 1:\n            should.append(Q('prefix', normalized_name=q))\n\n        query = request.es.query(\"dis_max\", queries=should)\n        query = query.suggest(\"name_suggestion\", q, term={\"field\": \"name\"})\n    else:\n        query = request.es.query()\n\n    if request.params.get(\"o\"):\n        query = query.sort(request.params[\"o\"])\n\n    if request.params.getall(\"c\"):\n        query = query.filter(\"terms\", classifiers=request.params.getall(\"c\"))\n\n    try:\n        page_num = int(request.params.get(\"page\", 1))\n    except ValueError:\n        raise HTTPBadRequest(\"'page' must be an integer.\")\n\n    page = ElasticsearchPage(\n        query,\n        page=page_num,\n        url_maker=paginate_url_factory(request),\n    )\n\n    if page.page_count and page_num > page.page_count:\n        return HTTPNotFound()\n\n    available_filters = collections.defaultdict(list)\n\n    for cls in request.db.query(Classifier).order_by(Classifier.classifier):\n        first, *_ = cls.classifier.split(' :: ')\n        available_filters[first].append(cls.classifier)\n\n    return {\n        \"page\": page,\n        \"term\": q,\n        \"order\": request.params.get(\"o\", ''),\n        \"available_filters\": sorted(available_filters.items()),\n        \"applied_filters\": request.params.getall(\"c\"),\n    }\n\n\n@view_config(\n    route_name=\"includes.current-user-indicator\",\n    renderer=\"includes/current-user-indicator.html\",\n    uses_session=True,\n)\ndef current_user_indicator(request):\n    return {}\n\n\n@view_config(route_name=\"health\", renderer=\"string\")\ndef health(request):\n    # This will ensure that we can access the database and run queries against\n    # it without doing anything that will take a lock or block other queries.\n    request.db.execute(\"SELECT 1\")\n\n    # Nothing will actually check this, but it's a little nicer to have\n    # something to return besides an empty body.\n    return \"OK\"\n", "path": "warehouse/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\nimport collections\n\nfrom pyramid.httpexceptions import (\n    HTTPException, HTTPSeeOther, HTTPMovedPermanently, HTTPNotFound,\n    HTTPBadRequest,\n)\nfrom pyramid.view import (\n    notfound_view_config, forbidden_view_config, view_config,\n)\nfrom elasticsearch_dsl import Q\nfrom sqlalchemy import func\nfrom sqlalchemy.orm import aliased, joinedload\n\nfrom warehouse.accounts import REDIRECT_FIELD_NAME\nfrom warehouse.accounts.models import User\nfrom warehouse.cache.origin import origin_cache\nfrom warehouse.cache.http import cache_control\nfrom warehouse.classifiers.models import Classifier\nfrom warehouse.packaging.models import Project, Release, File\nfrom warehouse.utils.row_counter import RowCount\nfrom warehouse.utils.paginate import ElasticsearchPage, paginate_url_factory\n\n\nSEARCH_FIELDS = [\n    \"author\", \"author_email\", \"description\", \"download_url\", \"home_page\",\n    \"keywords\", \"license\", \"maintainer\", \"maintainer_email\", \"normalized_name\",\n    \"platform\", \"summary\",\n]\nSEARCH_BOOSTS = {\n    \"normalized_name\": 10,\n    \"description\": 5,\n    \"keywords\": 5,\n    \"summary\": 5,\n}\nSEARCH_FILTER_ORDER = (\n    \"Programming Language\",\n    \"License\",\n    \"Framework\",\n    \"Topic\",\n    \"Intended Audience\",\n    \"Environment\",\n    \"Operating System\",\n    \"Natural Language\",\n    \"Development Status\",\n)\n\n\n@view_config(context=HTTPException)\n@notfound_view_config(append_slash=HTTPMovedPermanently)\ndef httpexception_view(exc, request):\n    return exc\n\n\n@forbidden_view_config()\ndef forbidden(exc, request):\n    # If the forbidden error is because the user isn't logged in, then we'll\n    # redirect them to the log in page.\n    if request.authenticated_userid is None:\n        url = request.route_url(\n            \"accounts.login\",\n            _query={REDIRECT_FIELD_NAME: request.path_qs},\n        )\n        return HTTPSeeOther(url)\n\n    # If we've reached here, then the user is logged in and they are genuinely\n    # not allowed to access this page.\n    # TODO: Style the forbidden page.\n    return exc\n\n\n@view_config(\n    route_name=\"robots.txt\",\n    renderer=\"robots.txt\",\n    decorator=[\n        cache_control(1 * 24 * 60 * 60),         # 1 day\n        origin_cache(\n            1 * 24 * 60 * 60,                    # 1 day\n            stale_while_revalidate=6 * 60 * 60,  # 6 hours\n            stale_if_error=1 * 24 * 60 * 60,     # 1 day\n        ),\n    ],\n)\ndef robotstxt(request):\n    request.response.content_type = \"text/plain\"\n    return {}\n\n\n@view_config(\n    route_name=\"index\",\n    renderer=\"index.html\",\n    decorator=[\n        origin_cache(\n            1 * 60 * 60,                      # 1 hour\n            stale_while_revalidate=10 * 60,   # 10 minutes\n            stale_if_error=1 * 24 * 60 * 60,  # 1 day\n            keys=[\"all-projects\"],\n        ),\n    ]\n)\ndef index(request):\n    project_names = [\n        r[0] for r in (\n            request.db.query(File.name)\n                   .group_by(File.name)\n                   .order_by(func.sum(File.downloads).desc())\n                   .limit(5)\n                   .all())\n    ]\n    release_a = aliased(\n        Release,\n        request.db.query(Release)\n                  .distinct(Release.name)\n                  .filter(Release.name.in_(project_names))\n                  .order_by(Release.name, Release._pypi_ordering.desc())\n                  .subquery(),\n    )\n    top_projects = (\n        request.db.query(release_a)\n               .options(joinedload(release_a.project))\n               .order_by(func.array_idx(project_names, release_a.name))\n               .all()\n    )\n\n    latest_releases = (\n        request.db.query(Release)\n                  .options(joinedload(Release.project))\n                  .order_by(Release.created.desc())\n                  .limit(5)\n                  .all()\n    )\n\n    counts = dict(\n        request.db.query(RowCount.table_name, RowCount.count)\n                  .filter(\n                      RowCount.table_name.in_([\n                          Project.__tablename__,\n                          Release.__tablename__,\n                          File.__tablename__,\n                          User.__tablename__,\n                      ]))\n                  .all()\n    )\n\n    return {\n        \"latest_releases\": latest_releases,\n        \"top_projects\": top_projects,\n        \"num_projects\": counts.get(Project.__tablename__, 0),\n        \"num_releases\": counts.get(Release.__tablename__, 0),\n        \"num_files\": counts.get(File.__tablename__, 0),\n        \"num_users\": counts.get(User.__tablename__, 0),\n    }\n\n\n@view_config(\n    route_name=\"search\",\n    renderer=\"search/results.html\",\n    decorator=[\n        origin_cache(\n            1 * 60 * 60,                      # 1 hour\n            stale_while_revalidate=10 * 60,   # 10 minutes\n            stale_if_error=1 * 24 * 60 * 60,  # 1 day\n            keys=[\"all-projects\"],\n        )\n    ],\n)\ndef search(request):\n\n    q = request.params.get(\"q\", '')\n\n    if q:\n        should = []\n        for field in SEARCH_FIELDS:\n            kw = {\"query\": q}\n            if field in SEARCH_BOOSTS:\n                kw[\"boost\"] = SEARCH_BOOSTS[field]\n            should.append(Q(\"match\", **{field: kw}))\n\n        # Add a prefix query if ``q`` is longer than one character.\n        if len(q) > 1:\n            should.append(Q('prefix', normalized_name=q))\n\n        query = request.es.query(\"dis_max\", queries=should)\n        query = query.suggest(\"name_suggestion\", q, term={\"field\": \"name\"})\n    else:\n        query = request.es.query()\n\n    if request.params.get(\"o\"):\n        query = query.sort(request.params[\"o\"])\n\n    if request.params.getall(\"c\"):\n        query = query.filter(\"terms\", classifiers=request.params.getall(\"c\"))\n\n    try:\n        page_num = int(request.params.get(\"page\", 1))\n    except ValueError:\n        raise HTTPBadRequest(\"'page' must be an integer.\")\n\n    page = ElasticsearchPage(\n        query,\n        page=page_num,\n        url_maker=paginate_url_factory(request),\n    )\n\n    if page.page_count and page_num > page.page_count:\n        return HTTPNotFound()\n\n    available_filters = collections.defaultdict(list)\n\n    for cls in request.db.query(Classifier).order_by(Classifier.classifier):\n        first, *_ = cls.classifier.split(' :: ')\n        available_filters[first].append(cls.classifier)\n\n    def filter_key(item):\n        try:\n            return 0, SEARCH_FILTER_ORDER.index(item[0]), item[0]\n        except ValueError:\n            return 1, 0, item[0]\n\n    return {\n        \"page\": page,\n        \"term\": q,\n        \"order\": request.params.get(\"o\", ''),\n        \"available_filters\": sorted(available_filters.items(), key=filter_key),\n        \"applied_filters\": request.params.getall(\"c\"),\n    }\n\n\n@view_config(\n    route_name=\"includes.current-user-indicator\",\n    renderer=\"includes/current-user-indicator.html\",\n    uses_session=True,\n)\ndef current_user_indicator(request):\n    return {}\n\n\n@view_config(route_name=\"health\", renderer=\"string\")\ndef health(request):\n    # This will ensure that we can access the database and run queries against\n    # it without doing anything that will take a lock or block other queries.\n    request.db.execute(\"SELECT 1\")\n\n    # Nothing will actually check this, but it's a little nicer to have\n    # something to return besides an empty body.\n    return \"OK\"\n", "path": "warehouse/views.py"}]}