We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
bodhi-push doesn't load the config file before starting the database connection
```bodhi-push``` doesn't load the config file before starting the database connection, which causes it to crash:

```
[bowlofeggs@bodhi-backend01 ~][PROD]$ sudo -u apache bodhi-push --releases 'f26,f25,f24,epel-7,EL-6' --username bowlofeggs
Traceback (most recent call last):
  File "/bin/bodhi-push", line 9, in <module>
    load_entry_point('bodhi-server==2.5.0', 'console_scripts', 'bodhi-push')()
  File "/usr/lib/python2.7/site-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python2.7/site-packages/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python2.7/site-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/bodhi/server/push.py", line 62, in push
    with get_db_factory()() as session:
  File "/usr/lib/python2.7/site-packages/bodhi/server/models.py", line 2438, in get_db_factory
    engine = engine_from_config(config, 'sqlalchemy.')
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/engine/__init__.py", line 426, in engine_from_config
    url = options.pop('url')
KeyError: 'url'
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bodhi/server/__init__.py`
Content:
```
1 # This program is free software; you can redistribute it and/or
2 # modify it under the terms of the GNU General Public License
3 # as published by the Free Software Foundation; either version 2
4 # of the License, or (at your option) any later version.
5 #
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9 # GNU General Public License for more details.
10 #
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
14 
15 from collections import defaultdict
16 import logging
17 
18 from cornice.validators import DEFAULT_FILTERS
19 from dogpile.cache import make_region
20 from munch import munchify
21 from pyramid.authentication import AuthTktAuthenticationPolicy
22 from pyramid.authorization import ACLAuthorizationPolicy
23 from pyramid.config import Configurator
24 from pyramid.exceptions import HTTPForbidden
25 from pyramid.renderers import JSONP
26 from pyramid.security import unauthenticated_userid
27 from pyramid.settings import asbool
28 from sqlalchemy import engine_from_config, event
29 from sqlalchemy.orm import scoped_session, sessionmaker
30 
31 from bodhi.server import bugs, buildsys, ffmarkdown
32 
33 
34 log = logging.getLogger(__name__)
35 
36 
37 # TODO -- someday move this externally to "fedora_flavored_markdown"
38 ffmarkdown.inject()
39 
40 
41 #
42 # Request methods
43 #
44 
45 def get_db_session_for_request(request=None):
46     """
47     This function returns a database session that is meant to be used for the given request.
48 
49     It handles rolling back or committing the session based on whether an exception occurred or
50     not. To get a database session that's not tied to the request/response cycle, just use the
51     :data:`Session` scoped session in this module.
52 
53     Args:
54         request (pyramid.request): The request object to create a session for.
55 
56     Returns:
57         sqlalchemy.orm.session.Session: A database session.
58     """
59     session = request.registry.sessionmaker()
60 
61     def cleanup(request):
62         """A post-request hook that commits the database changes if no exceptions occurred."""
63         if request.exception is not None:
64             session.rollback()
65         else:
66             session.commit()
67         session.close()
68 
69     request.add_finished_callback(cleanup)
70 
71     return session
72 
73 
74 def get_cacheregion(request):
75     region = make_region()
76     region.configure_from_config(request.registry.settings, "dogpile.cache.")
77     return region
78 
79 
80 def get_user(request):
81     from bodhi.server.models import User
82     userid = unauthenticated_userid(request)
83     if userid is not None:
84         user = request.db.query(User).filter_by(name=unicode(userid)).first()
85         # Why munch?  https://github.com/fedora-infra/bodhi/issues/473
86         return munchify(user.__json__(request=request))
87 
88 
89 def groupfinder(userid, request):
90     from bodhi.server.models import User
91     if request.user:
92         user = User.get(request.user.name, request.db)
93         return ['group:' + group.name for group in user.groups]
94 
95 
96 def get_koji(request):
97     return buildsys.get_session()
98 
99 
100 def get_buildinfo(request):
101     """
102     A per-request cache populated by the validators and shared with the views
103     to store frequently used package-specific data, like build tags and ACLs.
104     """
105     return defaultdict(dict)
106 
107 
108 def get_releases(request):
109     from bodhi.server.models import Release
110     return Release.all_releases(request.db)
111 
112 
113 #
114 # Cornice filters
115 #
116 
117 def exception_filter(response, request):
118     """Log exceptions that get thrown up to cornice"""
119     if isinstance(response, Exception):
120         log.exception('Unhandled exception raised:  %r' % response)
121     return response
122 
123 DEFAULT_FILTERS.insert(0, exception_filter)
124 
125 
126 #
127 # Bodhi initialization
128 #
129 
130 #: An SQLAlchemy scoped session with an engine configured using the settings in Bodhi's server
131 #: configuration file. Note that you *must* call :func:`initialize_db` before you can use this.
132 Session = scoped_session(sessionmaker())
133 
134 
135 def initialize_db(config):
136     """
137     Initialize the database using the given configuration.
138 
139     This *must* be called before you can use the :data:`Session` object.
140 
141     Args:
142         config (dict): The Bodhi server configuration dictionary.
143 
144     Returns:
145         sqlalchemy.engine: The database engine created from the configuration.
146     """
147     #: The SQLAlchemy database engine. This is constructed using the value of
148     #: ``DB_URL`` in :data:`config``.
149     engine = engine_from_config(config, 'sqlalchemy.')
150     # When using SQLite we need to make sure foreign keys are enabled:
151     # http://docs.sqlalchemy.org/en/latest/dialects/sqlite.html#foreign-key-support
152     if config['sqlalchemy.url'].startswith('sqlite:'):
153         event.listen(
154             engine,
155             'connect',
156             lambda db_con, con_record: db_con.execute('PRAGMA foreign_keys=ON')
157         )
158     Session.configure(bind=engine)
159     return engine
160 
161 
162 def main(global_config, testing=None, session=None, **settings):
163     """ This function returns a WSGI application """
164     # Setup our bugtracker and buildsystem
165     bugs.set_bugtracker()
166     buildsys.setup_buildsystem(settings)
167 
168     # Sessions & Caching
169     from pyramid.session import SignedCookieSessionFactory
170     session_factory = SignedCookieSessionFactory(settings['session.secret'])
171 
172     # Construct a list of all groups we're interested in
173     default = ' '.join([settings.get(key, '') for key in [
174         'important_groups',
175         'admin_packager_groups',
176         'mandatory_packager_groups',
177         'admin_groups',
178     ]])
179     # pyramid_fas_openid looks for this setting
180     settings['openid.groups'] = settings.get('openid.groups', default).split()
181 
182     config = Configurator(settings=settings, session_factory=session_factory)
183 
184     # Plugins
185     config.include('pyramid_mako')
186     config.include('cornice')
187 
188     # Initialize the database scoped session
189     initialize_db(settings)
190     config.registry.sessionmaker = Session.session_factory
191 
192     # Lazy-loaded memoized request properties
193     if session:
194         config.add_request_method(lambda _: session, 'db', reify=True)
195     else:
196         config.add_request_method(get_db_session_for_request, 'db', reify=True)
197 
198     config.add_request_method(get_user, 'user', reify=True)
199     config.add_request_method(get_koji, 'koji', reify=True)
200     config.add_request_method(get_cacheregion, 'cache', reify=True)
201     config.add_request_method(get_buildinfo, 'buildinfo', reify=True)
202     config.add_request_method(get_releases, 'releases', reify=True)
203 
204     # Templating
205     config.add_mako_renderer('.html', settings_prefix='mako.')
206     config.add_static_view('static', 'bodhi:server/static')
207 
208     from bodhi.server.renderers import rss, jpeg
209     config.add_renderer('rss', rss)
210     config.add_renderer('jpeg', jpeg)
211     config.add_renderer('jsonp', JSONP(param_name='callback'))
212 
213     # i18n
214     config.add_translation_dirs('bodhi:server/locale/')
215 
216     # Authentication & Authorization
217     if testing:
218         # use a permissive security policy while running unit tests
219         config.testing_securitypolicy(userid=testing, permissive=True)
220     else:
221         config.set_authentication_policy(AuthTktAuthenticationPolicy(
222             settings['authtkt.secret'], callback=groupfinder,
223             secure=asbool(settings['authtkt.secure']), hashalg='sha512'))
224         config.set_authorization_policy(ACLAuthorizationPolicy())
225 
226     # Frontpage
227     config.add_route('home', '/')
228 
229     # Views for creating new objects
230     config.add_route('new_update', '/updates/new')
231     config.add_route('new_override', '/overrides/new')
232     config.add_route('new_stack', '/stacks/new')
233 
234     # Metrics
235     config.add_route('metrics', '/metrics')
236     config.add_route('masher_status', '/masher/')
237 
238     # Auto-completion search
239     config.add_route('search_packages', '/search/packages')
240     config.add_route('latest_candidates', '/latest_candidates')
241     config.add_route('latest_builds', '/latest_builds')
242 
243     config.add_route('captcha_image', '/captcha/{cipherkey}/')
244 
245     # pyramid.openid
246     config.add_route('login', '/login')
247     config.add_view('bodhi.server.security.login', route_name='login')
248     config.add_view('bodhi.server.security.login', context=HTTPForbidden)
249     config.add_route('logout', '/logout')
250     config.add_view('bodhi.server.security.logout', route_name='logout')
251     config.add_route('verify_openid', pattern='/dologin.html')
252     config.add_view('pyramid_fas_openid.verify_openid', route_name='verify_openid')
253 
254     config.add_route('api_version', '/api_version')
255 
256     # The only user preference we have.
257     config.add_route('popup_toggle', '/popup_toggle')
258 
259     config.scan('bodhi.server.views')
260     config.scan('bodhi.server.services')
261     config.scan('bodhi.server.captcha')
262 
263     return config.make_wsgi_app()
264
```

Path: `bodhi/server/config.py`
Content:
```
1 # This program is free software; you can redistribute it and/or
2 # modify it under the terms of the GNU General Public License
3 # as published by the Free Software Foundation; either version 2
4 # of the License, or (at your option) any later version.
5 #
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9 # GNU General Public License for more details.
10 #
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
14 
15 import os
16 import logging
17 
18 from pyramid.paster import get_appsettings
19 
20 log = logging.getLogger('bodhi')
21 
22 
23 def get_configfile():
24     configfile = None
25     setupdir = os.path.join(os.path.dirname(os.path.dirname(__file__)), '..')
26     if configfile:
27         if not os.path.exists(configfile):
28             log.error("Cannot find config: %s" % configfile)
29             return
30     else:
31         for cfg in (os.path.join(setupdir, 'development.ini'),
32                     '/etc/bodhi/production.ini'):
33             if os.path.exists(cfg):
34                 configfile = cfg
35                 break
36         else:
37             log.error("Unable to find configuration to load!")
38     return configfile
39 
40 
41 class BodhiConfig(dict):
42     loaded = False
43 
44     def __getitem__(self, *args, **kw):
45         if not self.loaded:
46             self.load_config()
47         return super(BodhiConfig, self).__getitem__(*args, **kw)
48 
49     def get(self, *args, **kw):
50         if not self.loaded:
51             self.load_config()
52         return super(BodhiConfig, self).get(*args, **kw)
53 
54     def load_config(self):
55         configfile = get_configfile()
56         self.update(get_appsettings(configfile))
57         self.loaded = True
58 
59 
60 config = BodhiConfig()
61
```
--- 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/bodhi/server/__init__.py b/bodhi/server/__init__.py
--- a/bodhi/server/__init__.py
+++ b/bodhi/server/__init__.py
@@ -144,9 +144,10 @@
     Returns:
         sqlalchemy.engine: The database engine created from the configuration.
     """
-    #: The SQLAlchemy database engine. This is constructed using the value of
-    #: ``DB_URL`` in :data:`config``.
-    engine = engine_from_config(config, 'sqlalchemy.')
+    # The SQLAlchemy database engine. This is constructed using the value of
+    # ``DB_URL`` in :data:`config``. Note: A copy is provided since ``engine_from_config``
+    # uses ``pop``.
+    engine = engine_from_config(config.copy(), 'sqlalchemy.')
     # When using SQLite we need to make sure foreign keys are enabled:
     # http://docs.sqlalchemy.org/en/latest/dialects/sqlite.html#foreign-key-support
     if config['sqlalchemy.url'].startswith('sqlite:'):
diff --git a/bodhi/server/config.py b/bodhi/server/config.py
--- a/bodhi/server/config.py
+++ b/bodhi/server/config.py
@@ -51,6 +51,16 @@
             self.load_config()
         return super(BodhiConfig, self).get(*args, **kw)
 
+    def pop(self, *args, **kw):
+        if not self.loaded:
+            self.load_config()
+        return super(BodhiConfig, self).pop(*args, **kw)
+
+    def copy(self, *args, **kw):
+        if not self.loaded:
+            self.load_config()
+        return super(BodhiConfig, self).copy(*args, **kw)
+
     def load_config(self):
         configfile = get_configfile()
         self.update(get_appsettings(configfile))

{"golden_diff": "diff --git a/bodhi/server/__init__.py b/bodhi/server/__init__.py\n--- a/bodhi/server/__init__.py\n+++ b/bodhi/server/__init__.py\n@@ -144,9 +144,10 @@\n     Returns:\n         sqlalchemy.engine: The database engine created from the configuration.\n     \"\"\"\n-    #: The SQLAlchemy database engine. This is constructed using the value of\n-    #: ``DB_URL`` in :data:`config``.\n-    engine = engine_from_config(config, 'sqlalchemy.')\n+    # The SQLAlchemy database engine. This is constructed using the value of\n+    # ``DB_URL`` in :data:`config``. Note: A copy is provided since ``engine_from_config``\n+    # uses ``pop``.\n+    engine = engine_from_config(config.copy(), 'sqlalchemy.')\n     # When using SQLite we need to make sure foreign keys are enabled:\n     # http://docs.sqlalchemy.org/en/latest/dialects/sqlite.html#foreign-key-support\n     if config['sqlalchemy.url'].startswith('sqlite:'):\ndiff --git a/bodhi/server/config.py b/bodhi/server/config.py\n--- a/bodhi/server/config.py\n+++ b/bodhi/server/config.py\n@@ -51,6 +51,16 @@\n             self.load_config()\n         return super(BodhiConfig, self).get(*args, **kw)\n \n+    def pop(self, *args, **kw):\n+        if not self.loaded:\n+            self.load_config()\n+        return super(BodhiConfig, self).pop(*args, **kw)\n+\n+    def copy(self, *args, **kw):\n+        if not self.loaded:\n+            self.load_config()\n+        return super(BodhiConfig, self).copy(*args, **kw)\n+\n     def load_config(self):\n         configfile = get_configfile()\n         self.update(get_appsettings(configfile))\n", "issue": "bodhi-push doesn't load the config file before starting the database connection\n```bodhi-push``` doesn't load the config file before starting the database connection, which causes it to crash:\r\n\r\n```\r\n[bowlofeggs@bodhi-backend01 ~][PROD]$ sudo -u apache bodhi-push --releases 'f26,f25,f24,epel-7,EL-6' --username bowlofeggs\r\nTraceback (most recent call last):\r\n  File \"/bin/bodhi-push\", line 9, in <module>\r\n    load_entry_point('bodhi-server==2.5.0', 'console_scripts', 'bodhi-push')()\r\n  File \"/usr/lib/python2.7/site-packages/click/core.py\", line 722, in __call__\r\n    return self.main(*args, **kwargs)\r\n  File \"/usr/lib/python2.7/site-packages/click/core.py\", line 697, in main\r\n    rv = self.invoke(ctx)\r\n  File \"/usr/lib/python2.7/site-packages/click/core.py\", line 895, in invoke\r\n    return ctx.invoke(self.callback, **ctx.params)\r\n  File \"/usr/lib/python2.7/site-packages/click/core.py\", line 535, in invoke\r\n    return callback(*args, **kwargs)\r\n  File \"/usr/lib/python2.7/site-packages/bodhi/server/push.py\", line 62, in push\r\n    with get_db_factory()() as session:\r\n  File \"/usr/lib/python2.7/site-packages/bodhi/server/models.py\", line 2438, in get_db_factory\r\n    engine = engine_from_config(config, 'sqlalchemy.')\r\n  File \"/usr/lib64/python2.7/site-packages/sqlalchemy/engine/__init__.py\", line 426, in engine_from_config\r\n    url = options.pop('url')\r\nKeyError: 'url'\r\n```\n", "before_files": [{"content": "# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n\nfrom collections import defaultdict\nimport logging\n\nfrom cornice.validators import DEFAULT_FILTERS\nfrom dogpile.cache import make_region\nfrom munch import munchify\nfrom pyramid.authentication import AuthTktAuthenticationPolicy\nfrom pyramid.authorization import ACLAuthorizationPolicy\nfrom pyramid.config import Configurator\nfrom pyramid.exceptions import HTTPForbidden\nfrom pyramid.renderers import JSONP\nfrom pyramid.security import unauthenticated_userid\nfrom pyramid.settings import asbool\nfrom sqlalchemy import engine_from_config, event\nfrom sqlalchemy.orm import scoped_session, sessionmaker\n\nfrom bodhi.server import bugs, buildsys, ffmarkdown\n\n\nlog = logging.getLogger(__name__)\n\n\n# TODO -- someday move this externally to \"fedora_flavored_markdown\"\nffmarkdown.inject()\n\n\n#\n# Request methods\n#\n\ndef get_db_session_for_request(request=None):\n    \"\"\"\n    This function returns a database session that is meant to be used for the given request.\n\n    It handles rolling back or committing the session based on whether an exception occurred or\n    not. To get a database session that's not tied to the request/response cycle, just use the\n    :data:`Session` scoped session in this module.\n\n    Args:\n        request (pyramid.request): The request object to create a session for.\n\n    Returns:\n        sqlalchemy.orm.session.Session: A database session.\n    \"\"\"\n    session = request.registry.sessionmaker()\n\n    def cleanup(request):\n        \"\"\"A post-request hook that commits the database changes if no exceptions occurred.\"\"\"\n        if request.exception is not None:\n            session.rollback()\n        else:\n            session.commit()\n        session.close()\n\n    request.add_finished_callback(cleanup)\n\n    return session\n\n\ndef get_cacheregion(request):\n    region = make_region()\n    region.configure_from_config(request.registry.settings, \"dogpile.cache.\")\n    return region\n\n\ndef get_user(request):\n    from bodhi.server.models import User\n    userid = unauthenticated_userid(request)\n    if userid is not None:\n        user = request.db.query(User).filter_by(name=unicode(userid)).first()\n        # Why munch?  https://github.com/fedora-infra/bodhi/issues/473\n        return munchify(user.__json__(request=request))\n\n\ndef groupfinder(userid, request):\n    from bodhi.server.models import User\n    if request.user:\n        user = User.get(request.user.name, request.db)\n        return ['group:' + group.name for group in user.groups]\n\n\ndef get_koji(request):\n    return buildsys.get_session()\n\n\ndef get_buildinfo(request):\n    \"\"\"\n    A per-request cache populated by the validators and shared with the views\n    to store frequently used package-specific data, like build tags and ACLs.\n    \"\"\"\n    return defaultdict(dict)\n\n\ndef get_releases(request):\n    from bodhi.server.models import Release\n    return Release.all_releases(request.db)\n\n\n#\n# Cornice filters\n#\n\ndef exception_filter(response, request):\n    \"\"\"Log exceptions that get thrown up to cornice\"\"\"\n    if isinstance(response, Exception):\n        log.exception('Unhandled exception raised:  %r' % response)\n    return response\n\nDEFAULT_FILTERS.insert(0, exception_filter)\n\n\n#\n# Bodhi initialization\n#\n\n#: An SQLAlchemy scoped session with an engine configured using the settings in Bodhi's server\n#: configuration file. Note that you *must* call :func:`initialize_db` before you can use this.\nSession = scoped_session(sessionmaker())\n\n\ndef initialize_db(config):\n    \"\"\"\n    Initialize the database using the given configuration.\n\n    This *must* be called before you can use the :data:`Session` object.\n\n    Args:\n        config (dict): The Bodhi server configuration dictionary.\n\n    Returns:\n        sqlalchemy.engine: The database engine created from the configuration.\n    \"\"\"\n    #: The SQLAlchemy database engine. This is constructed using the value of\n    #: ``DB_URL`` in :data:`config``.\n    engine = engine_from_config(config, 'sqlalchemy.')\n    # When using SQLite we need to make sure foreign keys are enabled:\n    # http://docs.sqlalchemy.org/en/latest/dialects/sqlite.html#foreign-key-support\n    if config['sqlalchemy.url'].startswith('sqlite:'):\n        event.listen(\n            engine,\n            'connect',\n            lambda db_con, con_record: db_con.execute('PRAGMA foreign_keys=ON')\n        )\n    Session.configure(bind=engine)\n    return engine\n\n\ndef main(global_config, testing=None, session=None, **settings):\n    \"\"\" This function returns a WSGI application \"\"\"\n    # Setup our bugtracker and buildsystem\n    bugs.set_bugtracker()\n    buildsys.setup_buildsystem(settings)\n\n    # Sessions & Caching\n    from pyramid.session import SignedCookieSessionFactory\n    session_factory = SignedCookieSessionFactory(settings['session.secret'])\n\n    # Construct a list of all groups we're interested in\n    default = ' '.join([settings.get(key, '') for key in [\n        'important_groups',\n        'admin_packager_groups',\n        'mandatory_packager_groups',\n        'admin_groups',\n    ]])\n    # pyramid_fas_openid looks for this setting\n    settings['openid.groups'] = settings.get('openid.groups', default).split()\n\n    config = Configurator(settings=settings, session_factory=session_factory)\n\n    # Plugins\n    config.include('pyramid_mako')\n    config.include('cornice')\n\n    # Initialize the database scoped session\n    initialize_db(settings)\n    config.registry.sessionmaker = Session.session_factory\n\n    # Lazy-loaded memoized request properties\n    if session:\n        config.add_request_method(lambda _: session, 'db', reify=True)\n    else:\n        config.add_request_method(get_db_session_for_request, 'db', reify=True)\n\n    config.add_request_method(get_user, 'user', reify=True)\n    config.add_request_method(get_koji, 'koji', reify=True)\n    config.add_request_method(get_cacheregion, 'cache', reify=True)\n    config.add_request_method(get_buildinfo, 'buildinfo', reify=True)\n    config.add_request_method(get_releases, 'releases', reify=True)\n\n    # Templating\n    config.add_mako_renderer('.html', settings_prefix='mako.')\n    config.add_static_view('static', 'bodhi:server/static')\n\n    from bodhi.server.renderers import rss, jpeg\n    config.add_renderer('rss', rss)\n    config.add_renderer('jpeg', jpeg)\n    config.add_renderer('jsonp', JSONP(param_name='callback'))\n\n    # i18n\n    config.add_translation_dirs('bodhi:server/locale/')\n\n    # Authentication & Authorization\n    if testing:\n        # use a permissive security policy while running unit tests\n        config.testing_securitypolicy(userid=testing, permissive=True)\n    else:\n        config.set_authentication_policy(AuthTktAuthenticationPolicy(\n            settings['authtkt.secret'], callback=groupfinder,\n            secure=asbool(settings['authtkt.secure']), hashalg='sha512'))\n        config.set_authorization_policy(ACLAuthorizationPolicy())\n\n    # Frontpage\n    config.add_route('home', '/')\n\n    # Views for creating new objects\n    config.add_route('new_update', '/updates/new')\n    config.add_route('new_override', '/overrides/new')\n    config.add_route('new_stack', '/stacks/new')\n\n    # Metrics\n    config.add_route('metrics', '/metrics')\n    config.add_route('masher_status', '/masher/')\n\n    # Auto-completion search\n    config.add_route('search_packages', '/search/packages')\n    config.add_route('latest_candidates', '/latest_candidates')\n    config.add_route('latest_builds', '/latest_builds')\n\n    config.add_route('captcha_image', '/captcha/{cipherkey}/')\n\n    # pyramid.openid\n    config.add_route('login', '/login')\n    config.add_view('bodhi.server.security.login', route_name='login')\n    config.add_view('bodhi.server.security.login', context=HTTPForbidden)\n    config.add_route('logout', '/logout')\n    config.add_view('bodhi.server.security.logout', route_name='logout')\n    config.add_route('verify_openid', pattern='/dologin.html')\n    config.add_view('pyramid_fas_openid.verify_openid', route_name='verify_openid')\n\n    config.add_route('api_version', '/api_version')\n\n    # The only user preference we have.\n    config.add_route('popup_toggle', '/popup_toggle')\n\n    config.scan('bodhi.server.views')\n    config.scan('bodhi.server.services')\n    config.scan('bodhi.server.captcha')\n\n    return config.make_wsgi_app()\n", "path": "bodhi/server/__init__.py"}, {"content": "# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n\nimport os\nimport logging\n\nfrom pyramid.paster import get_appsettings\n\nlog = logging.getLogger('bodhi')\n\n\ndef get_configfile():\n    configfile = None\n    setupdir = os.path.join(os.path.dirname(os.path.dirname(__file__)), '..')\n    if configfile:\n        if not os.path.exists(configfile):\n            log.error(\"Cannot find config: %s\" % configfile)\n            return\n    else:\n        for cfg in (os.path.join(setupdir, 'development.ini'),\n                    '/etc/bodhi/production.ini'):\n            if os.path.exists(cfg):\n                configfile = cfg\n                break\n        else:\n            log.error(\"Unable to find configuration to load!\")\n    return configfile\n\n\nclass BodhiConfig(dict):\n    loaded = False\n\n    def __getitem__(self, *args, **kw):\n        if not self.loaded:\n            self.load_config()\n        return super(BodhiConfig, self).__getitem__(*args, **kw)\n\n    def get(self, *args, **kw):\n        if not self.loaded:\n            self.load_config()\n        return super(BodhiConfig, self).get(*args, **kw)\n\n    def load_config(self):\n        configfile = get_configfile()\n        self.update(get_appsettings(configfile))\n        self.loaded = True\n\n\nconfig = BodhiConfig()\n", "path": "bodhi/server/config.py"}], "after_files": [{"content": "# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n\nfrom collections import defaultdict\nimport logging\n\nfrom cornice.validators import DEFAULT_FILTERS\nfrom dogpile.cache import make_region\nfrom munch import munchify\nfrom pyramid.authentication import AuthTktAuthenticationPolicy\nfrom pyramid.authorization import ACLAuthorizationPolicy\nfrom pyramid.config import Configurator\nfrom pyramid.exceptions import HTTPForbidden\nfrom pyramid.renderers import JSONP\nfrom pyramid.security import unauthenticated_userid\nfrom pyramid.settings import asbool\nfrom sqlalchemy import engine_from_config, event\nfrom sqlalchemy.orm import scoped_session, sessionmaker\n\nfrom bodhi.server import bugs, buildsys, ffmarkdown\n\n\nlog = logging.getLogger(__name__)\n\n\n# TODO -- someday move this externally to \"fedora_flavored_markdown\"\nffmarkdown.inject()\n\n\n#\n# Request methods\n#\n\ndef get_db_session_for_request(request=None):\n    \"\"\"\n    This function returns a database session that is meant to be used for the given request.\n\n    It handles rolling back or committing the session based on whether an exception occurred or\n    not. To get a database session that's not tied to the request/response cycle, just use the\n    :data:`Session` scoped session in this module.\n\n    Args:\n        request (pyramid.request): The request object to create a session for.\n\n    Returns:\n        sqlalchemy.orm.session.Session: A database session.\n    \"\"\"\n    session = request.registry.sessionmaker()\n\n    def cleanup(request):\n        \"\"\"A post-request hook that commits the database changes if no exceptions occurred.\"\"\"\n        if request.exception is not None:\n            session.rollback()\n        else:\n            session.commit()\n        session.close()\n\n    request.add_finished_callback(cleanup)\n\n    return session\n\n\ndef get_cacheregion(request):\n    region = make_region()\n    region.configure_from_config(request.registry.settings, \"dogpile.cache.\")\n    return region\n\n\ndef get_user(request):\n    from bodhi.server.models import User\n    userid = unauthenticated_userid(request)\n    if userid is not None:\n        user = request.db.query(User).filter_by(name=unicode(userid)).first()\n        # Why munch?  https://github.com/fedora-infra/bodhi/issues/473\n        return munchify(user.__json__(request=request))\n\n\ndef groupfinder(userid, request):\n    from bodhi.server.models import User\n    if request.user:\n        user = User.get(request.user.name, request.db)\n        return ['group:' + group.name for group in user.groups]\n\n\ndef get_koji(request):\n    return buildsys.get_session()\n\n\ndef get_buildinfo(request):\n    \"\"\"\n    A per-request cache populated by the validators and shared with the views\n    to store frequently used package-specific data, like build tags and ACLs.\n    \"\"\"\n    return defaultdict(dict)\n\n\ndef get_releases(request):\n    from bodhi.server.models import Release\n    return Release.all_releases(request.db)\n\n\n#\n# Cornice filters\n#\n\ndef exception_filter(response, request):\n    \"\"\"Log exceptions that get thrown up to cornice\"\"\"\n    if isinstance(response, Exception):\n        log.exception('Unhandled exception raised:  %r' % response)\n    return response\n\nDEFAULT_FILTERS.insert(0, exception_filter)\n\n\n#\n# Bodhi initialization\n#\n\n#: An SQLAlchemy scoped session with an engine configured using the settings in Bodhi's server\n#: configuration file. Note that you *must* call :func:`initialize_db` before you can use this.\nSession = scoped_session(sessionmaker())\n\n\ndef initialize_db(config):\n    \"\"\"\n    Initialize the database using the given configuration.\n\n    This *must* be called before you can use the :data:`Session` object.\n\n    Args:\n        config (dict): The Bodhi server configuration dictionary.\n\n    Returns:\n        sqlalchemy.engine: The database engine created from the configuration.\n    \"\"\"\n    # The SQLAlchemy database engine. This is constructed using the value of\n    # ``DB_URL`` in :data:`config``. Note: A copy is provided since ``engine_from_config``\n    # uses ``pop``.\n    engine = engine_from_config(config.copy(), 'sqlalchemy.')\n    # When using SQLite we need to make sure foreign keys are enabled:\n    # http://docs.sqlalchemy.org/en/latest/dialects/sqlite.html#foreign-key-support\n    if config['sqlalchemy.url'].startswith('sqlite:'):\n        event.listen(\n            engine,\n            'connect',\n            lambda db_con, con_record: db_con.execute('PRAGMA foreign_keys=ON')\n        )\n    Session.configure(bind=engine)\n    return engine\n\n\ndef main(global_config, testing=None, session=None, **settings):\n    \"\"\" This function returns a WSGI application \"\"\"\n    # Setup our bugtracker and buildsystem\n    bugs.set_bugtracker()\n    buildsys.setup_buildsystem(settings)\n\n    # Sessions & Caching\n    from pyramid.session import SignedCookieSessionFactory\n    session_factory = SignedCookieSessionFactory(settings['session.secret'])\n\n    # Construct a list of all groups we're interested in\n    default = ' '.join([settings.get(key, '') for key in [\n        'important_groups',\n        'admin_packager_groups',\n        'mandatory_packager_groups',\n        'admin_groups',\n    ]])\n    # pyramid_fas_openid looks for this setting\n    settings['openid.groups'] = settings.get('openid.groups', default).split()\n\n    config = Configurator(settings=settings, session_factory=session_factory)\n\n    # Plugins\n    config.include('pyramid_mako')\n    config.include('cornice')\n\n    # Initialize the database scoped session\n    initialize_db(settings)\n    config.registry.sessionmaker = Session.session_factory\n\n    # Lazy-loaded memoized request properties\n    if session:\n        config.add_request_method(lambda _: session, 'db', reify=True)\n    else:\n        config.add_request_method(get_db_session_for_request, 'db', reify=True)\n\n    config.add_request_method(get_user, 'user', reify=True)\n    config.add_request_method(get_koji, 'koji', reify=True)\n    config.add_request_method(get_cacheregion, 'cache', reify=True)\n    config.add_request_method(get_buildinfo, 'buildinfo', reify=True)\n    config.add_request_method(get_releases, 'releases', reify=True)\n\n    # Templating\n    config.add_mako_renderer('.html', settings_prefix='mako.')\n    config.add_static_view('static', 'bodhi:server/static')\n\n    from bodhi.server.renderers import rss, jpeg\n    config.add_renderer('rss', rss)\n    config.add_renderer('jpeg', jpeg)\n    config.add_renderer('jsonp', JSONP(param_name='callback'))\n\n    # i18n\n    config.add_translation_dirs('bodhi:server/locale/')\n\n    # Authentication & Authorization\n    if testing:\n        # use a permissive security policy while running unit tests\n        config.testing_securitypolicy(userid=testing, permissive=True)\n    else:\n        config.set_authentication_policy(AuthTktAuthenticationPolicy(\n            settings['authtkt.secret'], callback=groupfinder,\n            secure=asbool(settings['authtkt.secure']), hashalg='sha512'))\n        config.set_authorization_policy(ACLAuthorizationPolicy())\n\n    # Frontpage\n    config.add_route('home', '/')\n\n    # Views for creating new objects\n    config.add_route('new_update', '/updates/new')\n    config.add_route('new_override', '/overrides/new')\n    config.add_route('new_stack', '/stacks/new')\n\n    # Metrics\n    config.add_route('metrics', '/metrics')\n    config.add_route('masher_status', '/masher/')\n\n    # Auto-completion search\n    config.add_route('search_packages', '/search/packages')\n    config.add_route('latest_candidates', '/latest_candidates')\n    config.add_route('latest_builds', '/latest_builds')\n\n    config.add_route('captcha_image', '/captcha/{cipherkey}/')\n\n    # pyramid.openid\n    config.add_route('login', '/login')\n    config.add_view('bodhi.server.security.login', route_name='login')\n    config.add_view('bodhi.server.security.login', context=HTTPForbidden)\n    config.add_route('logout', '/logout')\n    config.add_view('bodhi.server.security.logout', route_name='logout')\n    config.add_route('verify_openid', pattern='/dologin.html')\n    config.add_view('pyramid_fas_openid.verify_openid', route_name='verify_openid')\n\n    config.add_route('api_version', '/api_version')\n\n    # The only user preference we have.\n    config.add_route('popup_toggle', '/popup_toggle')\n\n    config.scan('bodhi.server.views')\n    config.scan('bodhi.server.services')\n    config.scan('bodhi.server.captcha')\n\n    return config.make_wsgi_app()\n", "path": "bodhi/server/__init__.py"}, {"content": "# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n\nimport os\nimport logging\n\nfrom pyramid.paster import get_appsettings\n\nlog = logging.getLogger('bodhi')\n\n\ndef get_configfile():\n    configfile = None\n    setupdir = os.path.join(os.path.dirname(os.path.dirname(__file__)), '..')\n    if configfile:\n        if not os.path.exists(configfile):\n            log.error(\"Cannot find config: %s\" % configfile)\n            return\n    else:\n        for cfg in (os.path.join(setupdir, 'development.ini'),\n                    '/etc/bodhi/production.ini'):\n            if os.path.exists(cfg):\n                configfile = cfg\n                break\n        else:\n            log.error(\"Unable to find configuration to load!\")\n    return configfile\n\n\nclass BodhiConfig(dict):\n    loaded = False\n\n    def __getitem__(self, *args, **kw):\n        if not self.loaded:\n            self.load_config()\n        return super(BodhiConfig, self).__getitem__(*args, **kw)\n\n    def get(self, *args, **kw):\n        if not self.loaded:\n            self.load_config()\n        return super(BodhiConfig, self).get(*args, **kw)\n\n    def pop(self, *args, **kw):\n        if not self.loaded:\n            self.load_config()\n        return super(BodhiConfig, self).pop(*args, **kw)\n\n    def copy(self, *args, **kw):\n        if not self.loaded:\n            self.load_config()\n        return super(BodhiConfig, self).copy(*args, **kw)\n\n    def load_config(self):\n        configfile = get_configfile()\n        self.update(get_appsettings(configfile))\n        self.loaded = True\n\n\nconfig = BodhiConfig()\n", "path": "bodhi/server/config.py"}]}