We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add Memcached to dockerfile and docker compose setup.
Following the addition of Memcached as a cache backend.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kinto/core/__init__.py`
Content:
```
1 """Main entry point
2 """
3 import logging
4 import pkg_resources
5 import tempfile
6 
7 from cornice import Service as CorniceService
8 from dockerflow import logging as dockerflow_logging
9 from pyramid.settings import aslist
10 
11 from kinto.core import errors
12 from kinto.core import events
13 from kinto.core.initialization import (  # NOQA
14     initialize, install_middlewares,
15     load_default_settings)
16 from kinto.core.utils import (
17     follow_subrequest, current_service, current_resource_name,
18     prefixed_userid, prefixed_principals, log_context)
19 
20 
21 logger = logging.getLogger(__name__)
22 
23 
24 # Module version, as defined in PEP-0396.
25 __version__ = pkg_resources.get_distribution('kinto').version  # FIXME?
26 
27 DEFAULT_SETTINGS = {
28     'backoff': None,
29     'batch_max_requests': 25,
30     'cache_backend': '',
31     'cache_url': '',
32     'cache_pool_size': 25,
33     'cache_prefix': '',
34     'cache_max_size_bytes': 524288,
35     'cors_origins': '*',
36     'cors_max_age_seconds': 3600,
37     'eos': None,
38     'eos_message': None,
39     'eos_url': None,
40     'error_info_link': 'https://github.com/Kinto/kinto/issues/',
41     'http_host': None,
42     'http_scheme': None,
43     'id_generator': 'kinto.core.storage.generators.UUID4',
44     'includes': '',
45     'initialization_sequence': (
46         'kinto.core.initialization.setup_request_bound_data',
47         'kinto.core.initialization.setup_json_serializer',
48         'kinto.core.initialization.setup_logging',
49         'kinto.core.initialization.setup_storage',
50         'kinto.core.initialization.setup_permission',
51         'kinto.core.initialization.setup_cache',
52         'kinto.core.initialization.setup_requests_scheme',
53         'kinto.core.initialization.setup_version_redirection',
54         'kinto.core.initialization.setup_deprecation',
55         'kinto.core.initialization.setup_authentication',
56         'kinto.core.initialization.setup_backoff',
57         'kinto.core.initialization.setup_statsd',
58         'kinto.core.initialization.setup_listeners',
59         'kinto.core.events.setup_transaction_hook',
60     ),
61     'event_listeners': '',
62     'heartbeat_timeout_seconds': 10,
63     'newrelic_config': None,
64     'newrelic_env': 'dev',
65     'paginate_by': None,
66     'pagination_token_validity_seconds': 10 * 60,
67     'permission_backend': '',
68     'permission_url': '',
69     'permission_pool_size': 25,
70     'profiler_dir': tempfile.gettempdir(),
71     'profiler_enabled': False,
72     'project_docs': '',
73     'project_name': '',
74     'project_version': '',
75     'readonly': False,
76     'retry_after_seconds': 30,
77     'statsd_backend': 'kinto.core.statsd',
78     'statsd_prefix': 'kinto.core',
79     'statsd_url': None,
80     'storage_backend': '',
81     'storage_url': '',
82     'storage_max_fetch_size': 10000,
83     'storage_pool_size': 25,
84     'tm.annotate_user': False,  # Do annotate transactions with the user-id.
85     'transaction_per_request': True,
86     'userid_hmac_secret': '',
87     'version_json_path': 'version.json',
88     'version_prefix_redirect_enabled': True,
89     'trailing_slash_redirect_enabled': True,
90     'multiauth.groupfinder': 'kinto.core.authorization.groupfinder',
91     'multiauth.policies': 'basicauth',
92     'multiauth.policy.basicauth.use': ('kinto.core.authentication.'
93                                        'BasicAuthAuthenticationPolicy'),
94     'multiauth.authorization_policy': ('kinto.core.authorization.'
95                                        'AuthorizationPolicy'),
96 }
97 
98 
99 class Service(CorniceService):
100     """Subclass of the default cornice service.
101 
102     This is useful in order to attach specific behaviours without monkey
103     patching the default cornice service (which would impact other uses of it)
104     """
105     default_cors_headers = ('Backoff', 'Retry-After', 'Alert',
106                             'Content-Length')
107 
108     def error_handler(self, request):
109         return errors.json_error_handler(request)
110 
111     @classmethod
112     def init_from_settings(cls, settings):
113         cls.cors_origins = tuple(aslist(settings['cors_origins']))
114         cors_max_age = settings['cors_max_age_seconds']
115         cls.cors_max_age = int(cors_max_age) if cors_max_age else None
116 
117 
118 class JsonLogFormatter(dockerflow_logging.JsonLogFormatter):
119     logger_name = 'kinto'
120 
121     @classmethod
122     def init_from_settings(cls, settings):
123         cls.logger_name = settings['project_name']
124 
125     def __init__(self, fmt=None, datefmt=None, style='%'):
126         # Do not let mozilla-cloud-services-logger constructor to improperly
127         # use style as the logger_name.
128         # See https://github.com/mozilla/mozilla-cloud-services-logger/issues/3
129         logger_name = self.logger_name
130         super().__init__(fmt, datefmt, style)
131         self.logger_name = logger_name
132 
133 
134 def includeme(config):
135     settings = config.get_settings()
136 
137     # Heartbeat registry.
138     config.registry.heartbeats = {}
139 
140     # Public settings registry.
141     config.registry.public_settings = {'batch_max_requests', 'readonly'}
142 
143     # Directive to declare arbitrary API capabilities.
144     def add_api_capability(config, identifier, description='', url='', **kw):
145         existing = config.registry.api_capabilities.get(identifier)
146         if existing:
147             error_msg = "The '{}' API capability was already registered ({})."
148             raise ValueError(error_msg.format(identifier, existing))
149 
150         capability = dict(description=description, url=url, **kw)
151         config.registry.api_capabilities[identifier] = capability
152 
153     config.add_directive('add_api_capability', add_api_capability)
154     config.registry.api_capabilities = {}
155 
156     # Resource events helpers.
157     config.add_request_method(events.get_resource_events,
158                               name='get_resource_events')
159     config.add_request_method(events.notify_resource_event,
160                               name='notify_resource_event')
161 
162     # Setup cornice.
163     config.include('cornice')
164 
165     # Setup cornice api documentation
166     config.include('cornice_swagger')
167 
168     # Per-request transaction.
169     config.include('pyramid_tm')
170 
171     # Add CORS settings to the base kinto.core Service class.
172     Service.init_from_settings(settings)
173 
174     # Use the project name as the main logger name (Logger field in MozLog).
175     JsonLogFormatter.init_from_settings(settings)
176 
177     # Setup components.
178     for step in aslist(settings['initialization_sequence']):
179         step_func = config.maybe_dotted(step)
180         step_func(config)
181 
182     # Custom helpers.
183     config.add_request_method(log_context)
184     config.add_request_method(follow_subrequest)
185     config.add_request_method(prefixed_userid, property=True)
186     config.add_request_method(prefixed_principals, reify=True)
187     config.add_request_method(lambda r: {
188         'id': r.prefixed_userid,
189         'principals': r.prefixed_principals},
190         name='get_user_info')
191     config.add_request_method(current_resource_name, reify=True)
192     config.add_request_method(current_service, reify=True)
193     config.commit()
194 
195     # Include plugins after init, unlike pyramid includes.
196     includes = aslist(settings['includes'])
197     for app in includes:
198         config.include(app)
199 
200     # # Show settings to output.
201     # for key, value in settings.items():
202     #     logger.info('Using {} = {}'.format(key, value))
203 
204     # Scan views.
205     config.scan('kinto.core.views')
206 
207     # Give sign of life.
208     msg = 'Running {project_name} {project_version}.'
209     logger.info(msg.format_map(settings))
210
```

Path: `kinto/core/storage/postgresql/client.py`
Content:
```
1 import contextlib
2 import logging
3 import warnings
4 from collections import defaultdict
5 
6 from kinto.core.storage import exceptions
7 from kinto.core.utils import sqlalchemy
8 import transaction as zope_transaction
9 
10 
11 logger = logging.getLogger(__name__)
12 
13 
14 class PostgreSQLClient:
15     def __init__(self, session_factory, commit_manually, invalidate):
16         self.session_factory = session_factory
17         self.commit_manually = commit_manually
18         self.invalidate = invalidate
19 
20     @contextlib.contextmanager
21     def connect(self, readonly=False, force_commit=False):
22         """
23         Pulls a connection from the pool when context is entered and
24         returns it when context is exited.
25 
26         A COMMIT is performed on the current transaction if everything went
27         well. Otherwise transaction is ROLLBACK, and everything cleaned up.
28         """
29         commit_manually = self.commit_manually and not readonly
30         session = None
31         try:
32             # Pull connection from pool.
33             session = self.session_factory()
34             # Start context
35             yield session
36             if not readonly and not self.commit_manually:
37                 # Mark session as dirty.
38                 self.invalidate(session)
39             # Success
40             if commit_manually:
41                 session.commit()
42             elif force_commit:
43                 # Commit like would do a succesful request.
44                 zope_transaction.commit()
45 
46         except sqlalchemy.exc.IntegrityError as e:
47             logger.error(e, exc_info=True)
48             if commit_manually:  # pragma: no branch
49                 session.rollback()
50             raise exceptions.IntegrityError(original=e) from e
51         except sqlalchemy.exc.SQLAlchemyError as e:
52             logger.error(e, exc_info=True)
53             if session and commit_manually:
54                 session.rollback()
55             raise exceptions.BackendError(original=e) from e
56         finally:
57             if session and self.commit_manually:
58                 # Give back to pool if commit done manually.
59                 session.close()
60 
61 
62 # Reuse existing client if same URL.
63 _CLIENTS = defaultdict(dict)
64 
65 
66 def create_from_config(config, prefix='', with_transaction=True):
67     """Create a PostgreSQLClient client using settings in the provided config.
68     """
69     if sqlalchemy is None:
70         message = ('PostgreSQL SQLAlchemy dependency missing. '
71                    'Refer to installation section in documentation.')
72         raise ImportWarning(message)
73 
74     from zope.sqlalchemy import ZopeTransactionExtension, invalidate
75     from sqlalchemy.orm import sessionmaker, scoped_session
76 
77     settings = {**config.get_settings()}
78     # Custom Kinto settings, unsupported by SQLAlchemy.
79     settings.pop(prefix + 'backend', None)
80     settings.pop(prefix + 'max_fetch_size', None)
81     settings.pop(prefix + 'max_size_bytes', None)
82     settings.pop(prefix + 'prefix', None)
83     settings.pop(prefix + 'strict_json', None)
84     transaction_per_request = with_transaction and settings.pop('transaction_per_request', False)
85 
86     url = settings[prefix + 'url']
87     existing_client = _CLIENTS[transaction_per_request].get(url)
88     if existing_client:
89         msg = ('Reuse existing PostgreSQL connection. '
90                'Parameters {}* will be ignored.'.format(prefix))
91         warnings.warn(msg)
92         return existing_client
93 
94     # Initialize SQLAlchemy engine from settings.
95     poolclass_key = prefix + 'poolclass'
96     settings.setdefault(poolclass_key, ('kinto.core.storage.postgresql.'
97                                         'pool.QueuePoolWithMaxBacklog'))
98     settings[poolclass_key] = config.maybe_dotted(settings[poolclass_key])
99     engine = sqlalchemy.engine_from_config(settings, prefix=prefix, url=url)
100 
101     # Initialize thread-safe session factory.
102     options = {}
103     if transaction_per_request:
104         # Plug with Pyramid transaction manager
105         options['extension'] = ZopeTransactionExtension()
106     session_factory = scoped_session(sessionmaker(bind=engine, **options))
107 
108     # Store one client per URI.
109     commit_manually = (not transaction_per_request)
110     client = PostgreSQLClient(session_factory, commit_manually, invalidate)
111     _CLIENTS[transaction_per_request][url] = client
112     return client
113
```
--- 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/kinto/core/__init__.py b/kinto/core/__init__.py
--- a/kinto/core/__init__.py
+++ b/kinto/core/__init__.py
@@ -28,6 +28,7 @@
     'backoff': None,
     'batch_max_requests': 25,
     'cache_backend': '',
+    'cache_hosts': '',
     'cache_url': '',
     'cache_pool_size': 25,
     'cache_prefix': '',
diff --git a/kinto/core/storage/postgresql/client.py b/kinto/core/storage/postgresql/client.py
--- a/kinto/core/storage/postgresql/client.py
+++ b/kinto/core/storage/postgresql/client.py
@@ -81,6 +81,7 @@
     settings.pop(prefix + 'max_size_bytes', None)
     settings.pop(prefix + 'prefix', None)
     settings.pop(prefix + 'strict_json', None)
+    settings.pop(prefix + 'hosts', None)
     transaction_per_request = with_transaction and settings.pop('transaction_per_request', False)
 
     url = settings[prefix + 'url']

{"golden_diff": "diff --git a/kinto/core/__init__.py b/kinto/core/__init__.py\n--- a/kinto/core/__init__.py\n+++ b/kinto/core/__init__.py\n@@ -28,6 +28,7 @@\n     'backoff': None,\n     'batch_max_requests': 25,\n     'cache_backend': '',\n+    'cache_hosts': '',\n     'cache_url': '',\n     'cache_pool_size': 25,\n     'cache_prefix': '',\ndiff --git a/kinto/core/storage/postgresql/client.py b/kinto/core/storage/postgresql/client.py\n--- a/kinto/core/storage/postgresql/client.py\n+++ b/kinto/core/storage/postgresql/client.py\n@@ -81,6 +81,7 @@\n     settings.pop(prefix + 'max_size_bytes', None)\n     settings.pop(prefix + 'prefix', None)\n     settings.pop(prefix + 'strict_json', None)\n+    settings.pop(prefix + 'hosts', None)\n     transaction_per_request = with_transaction and settings.pop('transaction_per_request', False)\n \n     url = settings[prefix + 'url']\n", "issue": "Add Memcached to dockerfile and docker compose setup.\nFollowing the addition of Memcached as a cache backend.\n", "before_files": [{"content": "\"\"\"Main entry point\n\"\"\"\nimport logging\nimport pkg_resources\nimport tempfile\n\nfrom cornice import Service as CorniceService\nfrom dockerflow import logging as dockerflow_logging\nfrom pyramid.settings import aslist\n\nfrom kinto.core import errors\nfrom kinto.core import events\nfrom kinto.core.initialization import (  # NOQA\n    initialize, install_middlewares,\n    load_default_settings)\nfrom kinto.core.utils import (\n    follow_subrequest, current_service, current_resource_name,\n    prefixed_userid, prefixed_principals, log_context)\n\n\nlogger = logging.getLogger(__name__)\n\n\n# Module version, as defined in PEP-0396.\n__version__ = pkg_resources.get_distribution('kinto').version  # FIXME?\n\nDEFAULT_SETTINGS = {\n    'backoff': None,\n    'batch_max_requests': 25,\n    'cache_backend': '',\n    'cache_url': '',\n    'cache_pool_size': 25,\n    'cache_prefix': '',\n    'cache_max_size_bytes': 524288,\n    'cors_origins': '*',\n    'cors_max_age_seconds': 3600,\n    'eos': None,\n    'eos_message': None,\n    'eos_url': None,\n    'error_info_link': 'https://github.com/Kinto/kinto/issues/',\n    'http_host': None,\n    'http_scheme': None,\n    'id_generator': 'kinto.core.storage.generators.UUID4',\n    'includes': '',\n    'initialization_sequence': (\n        'kinto.core.initialization.setup_request_bound_data',\n        'kinto.core.initialization.setup_json_serializer',\n        'kinto.core.initialization.setup_logging',\n        'kinto.core.initialization.setup_storage',\n        'kinto.core.initialization.setup_permission',\n        'kinto.core.initialization.setup_cache',\n        'kinto.core.initialization.setup_requests_scheme',\n        'kinto.core.initialization.setup_version_redirection',\n        'kinto.core.initialization.setup_deprecation',\n        'kinto.core.initialization.setup_authentication',\n        'kinto.core.initialization.setup_backoff',\n        'kinto.core.initialization.setup_statsd',\n        'kinto.core.initialization.setup_listeners',\n        'kinto.core.events.setup_transaction_hook',\n    ),\n    'event_listeners': '',\n    'heartbeat_timeout_seconds': 10,\n    'newrelic_config': None,\n    'newrelic_env': 'dev',\n    'paginate_by': None,\n    'pagination_token_validity_seconds': 10 * 60,\n    'permission_backend': '',\n    'permission_url': '',\n    'permission_pool_size': 25,\n    'profiler_dir': tempfile.gettempdir(),\n    'profiler_enabled': False,\n    'project_docs': '',\n    'project_name': '',\n    'project_version': '',\n    'readonly': False,\n    'retry_after_seconds': 30,\n    'statsd_backend': 'kinto.core.statsd',\n    'statsd_prefix': 'kinto.core',\n    'statsd_url': None,\n    'storage_backend': '',\n    'storage_url': '',\n    'storage_max_fetch_size': 10000,\n    'storage_pool_size': 25,\n    'tm.annotate_user': False,  # Do annotate transactions with the user-id.\n    'transaction_per_request': True,\n    'userid_hmac_secret': '',\n    'version_json_path': 'version.json',\n    'version_prefix_redirect_enabled': True,\n    'trailing_slash_redirect_enabled': True,\n    'multiauth.groupfinder': 'kinto.core.authorization.groupfinder',\n    'multiauth.policies': 'basicauth',\n    'multiauth.policy.basicauth.use': ('kinto.core.authentication.'\n                                       'BasicAuthAuthenticationPolicy'),\n    'multiauth.authorization_policy': ('kinto.core.authorization.'\n                                       'AuthorizationPolicy'),\n}\n\n\nclass Service(CorniceService):\n    \"\"\"Subclass of the default cornice service.\n\n    This is useful in order to attach specific behaviours without monkey\n    patching the default cornice service (which would impact other uses of it)\n    \"\"\"\n    default_cors_headers = ('Backoff', 'Retry-After', 'Alert',\n                            'Content-Length')\n\n    def error_handler(self, request):\n        return errors.json_error_handler(request)\n\n    @classmethod\n    def init_from_settings(cls, settings):\n        cls.cors_origins = tuple(aslist(settings['cors_origins']))\n        cors_max_age = settings['cors_max_age_seconds']\n        cls.cors_max_age = int(cors_max_age) if cors_max_age else None\n\n\nclass JsonLogFormatter(dockerflow_logging.JsonLogFormatter):\n    logger_name = 'kinto'\n\n    @classmethod\n    def init_from_settings(cls, settings):\n        cls.logger_name = settings['project_name']\n\n    def __init__(self, fmt=None, datefmt=None, style='%'):\n        # Do not let mozilla-cloud-services-logger constructor to improperly\n        # use style as the logger_name.\n        # See https://github.com/mozilla/mozilla-cloud-services-logger/issues/3\n        logger_name = self.logger_name\n        super().__init__(fmt, datefmt, style)\n        self.logger_name = logger_name\n\n\ndef includeme(config):\n    settings = config.get_settings()\n\n    # Heartbeat registry.\n    config.registry.heartbeats = {}\n\n    # Public settings registry.\n    config.registry.public_settings = {'batch_max_requests', 'readonly'}\n\n    # Directive to declare arbitrary API capabilities.\n    def add_api_capability(config, identifier, description='', url='', **kw):\n        existing = config.registry.api_capabilities.get(identifier)\n        if existing:\n            error_msg = \"The '{}' API capability was already registered ({}).\"\n            raise ValueError(error_msg.format(identifier, existing))\n\n        capability = dict(description=description, url=url, **kw)\n        config.registry.api_capabilities[identifier] = capability\n\n    config.add_directive('add_api_capability', add_api_capability)\n    config.registry.api_capabilities = {}\n\n    # Resource events helpers.\n    config.add_request_method(events.get_resource_events,\n                              name='get_resource_events')\n    config.add_request_method(events.notify_resource_event,\n                              name='notify_resource_event')\n\n    # Setup cornice.\n    config.include('cornice')\n\n    # Setup cornice api documentation\n    config.include('cornice_swagger')\n\n    # Per-request transaction.\n    config.include('pyramid_tm')\n\n    # Add CORS settings to the base kinto.core Service class.\n    Service.init_from_settings(settings)\n\n    # Use the project name as the main logger name (Logger field in MozLog).\n    JsonLogFormatter.init_from_settings(settings)\n\n    # Setup components.\n    for step in aslist(settings['initialization_sequence']):\n        step_func = config.maybe_dotted(step)\n        step_func(config)\n\n    # Custom helpers.\n    config.add_request_method(log_context)\n    config.add_request_method(follow_subrequest)\n    config.add_request_method(prefixed_userid, property=True)\n    config.add_request_method(prefixed_principals, reify=True)\n    config.add_request_method(lambda r: {\n        'id': r.prefixed_userid,\n        'principals': r.prefixed_principals},\n        name='get_user_info')\n    config.add_request_method(current_resource_name, reify=True)\n    config.add_request_method(current_service, reify=True)\n    config.commit()\n\n    # Include plugins after init, unlike pyramid includes.\n    includes = aslist(settings['includes'])\n    for app in includes:\n        config.include(app)\n\n    # # Show settings to output.\n    # for key, value in settings.items():\n    #     logger.info('Using {} = {}'.format(key, value))\n\n    # Scan views.\n    config.scan('kinto.core.views')\n\n    # Give sign of life.\n    msg = 'Running {project_name} {project_version}.'\n    logger.info(msg.format_map(settings))\n", "path": "kinto/core/__init__.py"}, {"content": "import contextlib\nimport logging\nimport warnings\nfrom collections import defaultdict\n\nfrom kinto.core.storage import exceptions\nfrom kinto.core.utils import sqlalchemy\nimport transaction as zope_transaction\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass PostgreSQLClient:\n    def __init__(self, session_factory, commit_manually, invalidate):\n        self.session_factory = session_factory\n        self.commit_manually = commit_manually\n        self.invalidate = invalidate\n\n    @contextlib.contextmanager\n    def connect(self, readonly=False, force_commit=False):\n        \"\"\"\n        Pulls a connection from the pool when context is entered and\n        returns it when context is exited.\n\n        A COMMIT is performed on the current transaction if everything went\n        well. Otherwise transaction is ROLLBACK, and everything cleaned up.\n        \"\"\"\n        commit_manually = self.commit_manually and not readonly\n        session = None\n        try:\n            # Pull connection from pool.\n            session = self.session_factory()\n            # Start context\n            yield session\n            if not readonly and not self.commit_manually:\n                # Mark session as dirty.\n                self.invalidate(session)\n            # Success\n            if commit_manually:\n                session.commit()\n            elif force_commit:\n                # Commit like would do a succesful request.\n                zope_transaction.commit()\n\n        except sqlalchemy.exc.IntegrityError as e:\n            logger.error(e, exc_info=True)\n            if commit_manually:  # pragma: no branch\n                session.rollback()\n            raise exceptions.IntegrityError(original=e) from e\n        except sqlalchemy.exc.SQLAlchemyError as e:\n            logger.error(e, exc_info=True)\n            if session and commit_manually:\n                session.rollback()\n            raise exceptions.BackendError(original=e) from e\n        finally:\n            if session and self.commit_manually:\n                # Give back to pool if commit done manually.\n                session.close()\n\n\n# Reuse existing client if same URL.\n_CLIENTS = defaultdict(dict)\n\n\ndef create_from_config(config, prefix='', with_transaction=True):\n    \"\"\"Create a PostgreSQLClient client using settings in the provided config.\n    \"\"\"\n    if sqlalchemy is None:\n        message = ('PostgreSQL SQLAlchemy dependency missing. '\n                   'Refer to installation section in documentation.')\n        raise ImportWarning(message)\n\n    from zope.sqlalchemy import ZopeTransactionExtension, invalidate\n    from sqlalchemy.orm import sessionmaker, scoped_session\n\n    settings = {**config.get_settings()}\n    # Custom Kinto settings, unsupported by SQLAlchemy.\n    settings.pop(prefix + 'backend', None)\n    settings.pop(prefix + 'max_fetch_size', None)\n    settings.pop(prefix + 'max_size_bytes', None)\n    settings.pop(prefix + 'prefix', None)\n    settings.pop(prefix + 'strict_json', None)\n    transaction_per_request = with_transaction and settings.pop('transaction_per_request', False)\n\n    url = settings[prefix + 'url']\n    existing_client = _CLIENTS[transaction_per_request].get(url)\n    if existing_client:\n        msg = ('Reuse existing PostgreSQL connection. '\n               'Parameters {}* will be ignored.'.format(prefix))\n        warnings.warn(msg)\n        return existing_client\n\n    # Initialize SQLAlchemy engine from settings.\n    poolclass_key = prefix + 'poolclass'\n    settings.setdefault(poolclass_key, ('kinto.core.storage.postgresql.'\n                                        'pool.QueuePoolWithMaxBacklog'))\n    settings[poolclass_key] = config.maybe_dotted(settings[poolclass_key])\n    engine = sqlalchemy.engine_from_config(settings, prefix=prefix, url=url)\n\n    # Initialize thread-safe session factory.\n    options = {}\n    if transaction_per_request:\n        # Plug with Pyramid transaction manager\n        options['extension'] = ZopeTransactionExtension()\n    session_factory = scoped_session(sessionmaker(bind=engine, **options))\n\n    # Store one client per URI.\n    commit_manually = (not transaction_per_request)\n    client = PostgreSQLClient(session_factory, commit_manually, invalidate)\n    _CLIENTS[transaction_per_request][url] = client\n    return client\n", "path": "kinto/core/storage/postgresql/client.py"}], "after_files": [{"content": "\"\"\"Main entry point\n\"\"\"\nimport logging\nimport pkg_resources\nimport tempfile\n\nfrom cornice import Service as CorniceService\nfrom dockerflow import logging as dockerflow_logging\nfrom pyramid.settings import aslist\n\nfrom kinto.core import errors\nfrom kinto.core import events\nfrom kinto.core.initialization import (  # NOQA\n    initialize, install_middlewares,\n    load_default_settings)\nfrom kinto.core.utils import (\n    follow_subrequest, current_service, current_resource_name,\n    prefixed_userid, prefixed_principals, log_context)\n\n\nlogger = logging.getLogger(__name__)\n\n\n# Module version, as defined in PEP-0396.\n__version__ = pkg_resources.get_distribution('kinto').version  # FIXME?\n\nDEFAULT_SETTINGS = {\n    'backoff': None,\n    'batch_max_requests': 25,\n    'cache_backend': '',\n    'cache_hosts': '',\n    'cache_url': '',\n    'cache_pool_size': 25,\n    'cache_prefix': '',\n    'cache_max_size_bytes': 524288,\n    'cors_origins': '*',\n    'cors_max_age_seconds': 3600,\n    'eos': None,\n    'eos_message': None,\n    'eos_url': None,\n    'error_info_link': 'https://github.com/Kinto/kinto/issues/',\n    'http_host': None,\n    'http_scheme': None,\n    'id_generator': 'kinto.core.storage.generators.UUID4',\n    'includes': '',\n    'initialization_sequence': (\n        'kinto.core.initialization.setup_request_bound_data',\n        'kinto.core.initialization.setup_json_serializer',\n        'kinto.core.initialization.setup_logging',\n        'kinto.core.initialization.setup_storage',\n        'kinto.core.initialization.setup_permission',\n        'kinto.core.initialization.setup_cache',\n        'kinto.core.initialization.setup_requests_scheme',\n        'kinto.core.initialization.setup_version_redirection',\n        'kinto.core.initialization.setup_deprecation',\n        'kinto.core.initialization.setup_authentication',\n        'kinto.core.initialization.setup_backoff',\n        'kinto.core.initialization.setup_statsd',\n        'kinto.core.initialization.setup_listeners',\n        'kinto.core.events.setup_transaction_hook',\n    ),\n    'event_listeners': '',\n    'heartbeat_timeout_seconds': 10,\n    'newrelic_config': None,\n    'newrelic_env': 'dev',\n    'paginate_by': None,\n    'pagination_token_validity_seconds': 10 * 60,\n    'permission_backend': '',\n    'permission_url': '',\n    'permission_pool_size': 25,\n    'profiler_dir': tempfile.gettempdir(),\n    'profiler_enabled': False,\n    'project_docs': '',\n    'project_name': '',\n    'project_version': '',\n    'readonly': False,\n    'retry_after_seconds': 30,\n    'statsd_backend': 'kinto.core.statsd',\n    'statsd_prefix': 'kinto.core',\n    'statsd_url': None,\n    'storage_backend': '',\n    'storage_url': '',\n    'storage_max_fetch_size': 10000,\n    'storage_pool_size': 25,\n    'tm.annotate_user': False,  # Do annotate transactions with the user-id.\n    'transaction_per_request': True,\n    'userid_hmac_secret': '',\n    'version_json_path': 'version.json',\n    'version_prefix_redirect_enabled': True,\n    'trailing_slash_redirect_enabled': True,\n    'multiauth.groupfinder': 'kinto.core.authorization.groupfinder',\n    'multiauth.policies': 'basicauth',\n    'multiauth.policy.basicauth.use': ('kinto.core.authentication.'\n                                       'BasicAuthAuthenticationPolicy'),\n    'multiauth.authorization_policy': ('kinto.core.authorization.'\n                                       'AuthorizationPolicy'),\n}\n\n\nclass Service(CorniceService):\n    \"\"\"Subclass of the default cornice service.\n\n    This is useful in order to attach specific behaviours without monkey\n    patching the default cornice service (which would impact other uses of it)\n    \"\"\"\n    default_cors_headers = ('Backoff', 'Retry-After', 'Alert',\n                            'Content-Length')\n\n    def error_handler(self, request):\n        return errors.json_error_handler(request)\n\n    @classmethod\n    def init_from_settings(cls, settings):\n        cls.cors_origins = tuple(aslist(settings['cors_origins']))\n        cors_max_age = settings['cors_max_age_seconds']\n        cls.cors_max_age = int(cors_max_age) if cors_max_age else None\n\n\nclass JsonLogFormatter(dockerflow_logging.JsonLogFormatter):\n    logger_name = 'kinto'\n\n    @classmethod\n    def init_from_settings(cls, settings):\n        cls.logger_name = settings['project_name']\n\n    def __init__(self, fmt=None, datefmt=None, style='%'):\n        # Do not let mozilla-cloud-services-logger constructor to improperly\n        # use style as the logger_name.\n        # See https://github.com/mozilla/mozilla-cloud-services-logger/issues/3\n        logger_name = self.logger_name\n        super().__init__(fmt, datefmt, style)\n        self.logger_name = logger_name\n\n\ndef includeme(config):\n    settings = config.get_settings()\n\n    # Heartbeat registry.\n    config.registry.heartbeats = {}\n\n    # Public settings registry.\n    config.registry.public_settings = {'batch_max_requests', 'readonly'}\n\n    # Directive to declare arbitrary API capabilities.\n    def add_api_capability(config, identifier, description='', url='', **kw):\n        existing = config.registry.api_capabilities.get(identifier)\n        if existing:\n            error_msg = \"The '{}' API capability was already registered ({}).\"\n            raise ValueError(error_msg.format(identifier, existing))\n\n        capability = dict(description=description, url=url, **kw)\n        config.registry.api_capabilities[identifier] = capability\n\n    config.add_directive('add_api_capability', add_api_capability)\n    config.registry.api_capabilities = {}\n\n    # Resource events helpers.\n    config.add_request_method(events.get_resource_events,\n                              name='get_resource_events')\n    config.add_request_method(events.notify_resource_event,\n                              name='notify_resource_event')\n\n    # Setup cornice.\n    config.include('cornice')\n\n    # Setup cornice api documentation\n    config.include('cornice_swagger')\n\n    # Per-request transaction.\n    config.include('pyramid_tm')\n\n    # Add CORS settings to the base kinto.core Service class.\n    Service.init_from_settings(settings)\n\n    # Use the project name as the main logger name (Logger field in MozLog).\n    JsonLogFormatter.init_from_settings(settings)\n\n    # Setup components.\n    for step in aslist(settings['initialization_sequence']):\n        step_func = config.maybe_dotted(step)\n        step_func(config)\n\n    # Custom helpers.\n    config.add_request_method(log_context)\n    config.add_request_method(follow_subrequest)\n    config.add_request_method(prefixed_userid, property=True)\n    config.add_request_method(prefixed_principals, reify=True)\n    config.add_request_method(lambda r: {\n        'id': r.prefixed_userid,\n        'principals': r.prefixed_principals},\n        name='get_user_info')\n    config.add_request_method(current_resource_name, reify=True)\n    config.add_request_method(current_service, reify=True)\n    config.commit()\n\n    # Include plugins after init, unlike pyramid includes.\n    includes = aslist(settings['includes'])\n    for app in includes:\n        config.include(app)\n\n    # # Show settings to output.\n    # for key, value in settings.items():\n    #     logger.info('Using {} = {}'.format(key, value))\n\n    # Scan views.\n    config.scan('kinto.core.views')\n\n    # Give sign of life.\n    msg = 'Running {project_name} {project_version}.'\n    logger.info(msg.format_map(settings))\n", "path": "kinto/core/__init__.py"}, {"content": "import contextlib\nimport logging\nimport warnings\nfrom collections import defaultdict\n\nfrom kinto.core.storage import exceptions\nfrom kinto.core.utils import sqlalchemy\nimport transaction as zope_transaction\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass PostgreSQLClient:\n    def __init__(self, session_factory, commit_manually, invalidate):\n        self.session_factory = session_factory\n        self.commit_manually = commit_manually\n        self.invalidate = invalidate\n\n    @contextlib.contextmanager\n    def connect(self, readonly=False, force_commit=False):\n        \"\"\"\n        Pulls a connection from the pool when context is entered and\n        returns it when context is exited.\n\n        A COMMIT is performed on the current transaction if everything went\n        well. Otherwise transaction is ROLLBACK, and everything cleaned up.\n        \"\"\"\n        commit_manually = self.commit_manually and not readonly\n        session = None\n        try:\n            # Pull connection from pool.\n            session = self.session_factory()\n            # Start context\n            yield session\n            if not readonly and not self.commit_manually:\n                # Mark session as dirty.\n                self.invalidate(session)\n            # Success\n            if commit_manually:\n                session.commit()\n            elif force_commit:\n                # Commit like would do a succesful request.\n                zope_transaction.commit()\n\n        except sqlalchemy.exc.IntegrityError as e:\n            logger.error(e, exc_info=True)\n            if commit_manually:  # pragma: no branch\n                session.rollback()\n            raise exceptions.IntegrityError(original=e) from e\n        except sqlalchemy.exc.SQLAlchemyError as e:\n            logger.error(e, exc_info=True)\n            if session and commit_manually:\n                session.rollback()\n            raise exceptions.BackendError(original=e) from e\n        finally:\n            if session and self.commit_manually:\n                # Give back to pool if commit done manually.\n                session.close()\n\n\n# Reuse existing client if same URL.\n_CLIENTS = defaultdict(dict)\n\n\ndef create_from_config(config, prefix='', with_transaction=True):\n    \"\"\"Create a PostgreSQLClient client using settings in the provided config.\n    \"\"\"\n    if sqlalchemy is None:\n        message = ('PostgreSQL SQLAlchemy dependency missing. '\n                   'Refer to installation section in documentation.')\n        raise ImportWarning(message)\n\n    from zope.sqlalchemy import ZopeTransactionExtension, invalidate\n    from sqlalchemy.orm import sessionmaker, scoped_session\n\n    settings = {**config.get_settings()}\n    # Custom Kinto settings, unsupported by SQLAlchemy.\n    settings.pop(prefix + 'backend', None)\n    settings.pop(prefix + 'max_fetch_size', None)\n    settings.pop(prefix + 'max_size_bytes', None)\n    settings.pop(prefix + 'prefix', None)\n    settings.pop(prefix + 'strict_json', None)\n    settings.pop(prefix + 'hosts', None)\n    transaction_per_request = with_transaction and settings.pop('transaction_per_request', False)\n\n    url = settings[prefix + 'url']\n    existing_client = _CLIENTS[transaction_per_request].get(url)\n    if existing_client:\n        msg = ('Reuse existing PostgreSQL connection. '\n               'Parameters {}* will be ignored.'.format(prefix))\n        warnings.warn(msg)\n        return existing_client\n\n    # Initialize SQLAlchemy engine from settings.\n    poolclass_key = prefix + 'poolclass'\n    settings.setdefault(poolclass_key, ('kinto.core.storage.postgresql.'\n                                        'pool.QueuePoolWithMaxBacklog'))\n    settings[poolclass_key] = config.maybe_dotted(settings[poolclass_key])\n    engine = sqlalchemy.engine_from_config(settings, prefix=prefix, url=url)\n\n    # Initialize thread-safe session factory.\n    options = {}\n    if transaction_per_request:\n        # Plug with Pyramid transaction manager\n        options['extension'] = ZopeTransactionExtension()\n    session_factory = scoped_session(sessionmaker(bind=engine, **options))\n\n    # Store one client per URI.\n    commit_manually = (not transaction_per_request)\n    client = PostgreSQLClient(session_factory, commit_manually, invalidate)\n    _CLIENTS[transaction_per_request][url] = client\n    return client\n", "path": "kinto/core/storage/postgresql/client.py"}]}