We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Intermittent duplicate key errors when creating default sysadmin
**CKAN version**

CKAN 2.9.x. Does not appear to affect 2.8.

**Describe the bug**

When our continuous integration tests initialise a test CKAN 2.9 instance, they sometimes encounter a duplicate key exception when CKAN is attempting to create the 'default' sysadmin account. There does not appear to be any specific pattern to when the errors occur; re-running the build may resolve it, or not. This did not occur on CKAN 2.8.

**Steps to reproduce**

Our test scripts run the following CLI commands:

ckan -c /etc/ckan/default/production.ini db clean --yes
ckan -c /etc/ckan/default/production.ini db init
ckan -c /etc/ckan/default/production.ini comments initdb
ckan -c /etc/ckan/default/production.ini comments updatedb
ckan -c /etc/ckan/default/production.ini comments init_notifications_db

**Additional details**
Sample failed build:

https://github.com/qld-gov-au/ckanext-ytp-comments/runs/4480610398?check_suite_focus=true

(Search for "already exists" to locate the stack trace)

NB Although the error actually occurred on that run during a `ckanext-ytp-comments` command, it was not specific to the extension, as shown by an excerpt from the stack trace:

        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/cli/cli.py", line 102, in _init_ckan_config
        ckan_1                |     ctx.obj = CkanCommand(value)
        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/cli/cli.py", line 52, in __init__
        ckan_1                |     self.app = make_app(self.config)
        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/config/middleware/__init__.py", line 56, in make_app
        ckan_1                |     load_environment(conf)
        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/config/environment.py", line 123, in load_environment
        ckan_1                |     p.load_all()
        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/plugins/core.py", line 161, in load_all
        ckan_1                |     unload_all()
        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/plugins/core.py", line 208, in unload_all
        ckan_1                |     unload(*reversed(_PLUGINS))
        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/plugins/core.py", line 236, in unload
        ckan_1                |     plugins_update()
        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/plugins/core.py", line 153, in plugins_update
        ckan_1                |     environment.update_config()
        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/config/environment.py", line 322, in update_config
        ckan_1                |     logic.get_action('get_site_user')({'ignore_auth': True}, None)
        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/logic/__init__.py", line 477, in wrapped
        ckan_1                |     result = _action(context, data_dict, **kw)
        ckan_1                |   File "/app/ckan/default/src/ckan/ckan/logic/action/get.py", line 2398, in get_site_user
        ckan_1                |     model.Session.flush()

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ckan/config/environment.py`
Content:
```
1 # encoding: utf-8
2 
3 '''CKAN environment configuration'''
4 import os
5 import logging
6 import warnings
7 import pytz
8 
9 import sqlalchemy
10 
11 import ckan.model as model
12 import ckan.plugins as p
13 import ckan.lib.plugins as lib_plugins
14 import ckan.lib.helpers as helpers
15 import ckan.lib.app_globals as app_globals
16 from ckan.lib.redis import is_redis_available
17 import ckan.lib.search as search
18 import ckan.logic as logic
19 import ckan.authz as authz
20 from ckan.lib.webassets_tools import webassets_init
21 from ckan.lib.i18n import build_js_translations
22 
23 from ckan.common import config, config_declaration
24 from ckan.exceptions import CkanConfigurationException
25 log = logging.getLogger(__name__)
26 
27 # Suppress benign warning 'Unbuilt egg for setuptools'
28 warnings.simplefilter('ignore', UserWarning)
29 
30 
31 def load_environment(conf):
32     """
33     Configure the Pylons environment via the ``pylons.config`` object. This
34     code should only need to be run once.
35     """
36     os.environ['CKAN_CONFIG'] = conf['__file__']
37 
38     valid_base_public_folder_names = ['public']
39     static_files = conf.get('ckan.base_public_folder', 'public')
40     conf['ckan.base_public_folder'] = static_files
41 
42     if static_files not in valid_base_public_folder_names:
43         raise CkanConfigurationException(
44             'You provided an invalid value for ckan.base_public_folder. '
45             'Possible values are: "public".'
46         )
47 
48     log.info('Loading static files from %s' % static_files)
49 
50     # Initialize main CKAN config object
51     config.update(conf)
52 
53     # Setup the SQLAlchemy database engine
54     # Suppress a couple of sqlalchemy warnings
55     msgs = ['^Unicode type received non-unicode bind param value',
56             "^Did not recognize type 'BIGINT' of column 'size'",
57             "^Did not recognize type 'tsvector' of column 'search_vector'"
58             ]
59     for msg in msgs:
60         warnings.filterwarnings('ignore', msg, sqlalchemy.exc.SAWarning)
61 
62     # load all CKAN plugins
63     p.load_all()
64 
65     # Check Redis availability
66     if not is_redis_available():
67         log.critical('Could not connect to Redis.')
68 
69     app_globals.reset()
70 
71     # issue #3260: remove idle transaction
72     # Session that was used for getting all config params nor committed,
73     # neither removed and we have idle connection as result
74     model.Session.commit()
75 
76     # Build JavaScript translations. Must be done after plugins have
77     # been loaded.
78     build_js_translations()
79 
80 
81 # A mapping of config settings that can be overridden by env vars.
82 # Note: Do not remove the following lines, they are used in the docs
83 # Start CONFIG_FROM_ENV_VARS
84 CONFIG_FROM_ENV_VARS = {
85     'sqlalchemy.url': 'CKAN_SQLALCHEMY_URL',
86     'ckan.datastore.write_url': 'CKAN_DATASTORE_WRITE_URL',
87     'ckan.datastore.read_url': 'CKAN_DATASTORE_READ_URL',
88     'ckan.redis.url': 'CKAN_REDIS_URL',
89     'solr_url': 'CKAN_SOLR_URL',
90     'solr_user': 'CKAN_SOLR_USER',
91     'solr_password': 'CKAN_SOLR_PASSWORD',
92     'ckan.site_id': 'CKAN_SITE_ID',
93     'ckan.site_url': 'CKAN_SITE_URL',
94     'ckan.storage_path': 'CKAN_STORAGE_PATH',
95     'ckan.datapusher.url': 'CKAN_DATAPUSHER_URL',
96     'smtp.server': 'CKAN_SMTP_SERVER',
97     'smtp.starttls': 'CKAN_SMTP_STARTTLS',
98     'smtp.user': 'CKAN_SMTP_USER',
99     'smtp.password': 'CKAN_SMTP_PASSWORD',
100     'smtp.mail_from': 'CKAN_SMTP_MAIL_FROM',
101     'ckan.max_resource_size': 'CKAN_MAX_UPLOAD_SIZE_MB'
102 }
103 # End CONFIG_FROM_ENV_VARS
104 
105 
106 def update_config():
107     ''' This code needs to be run when the config is changed to take those
108     changes into account. It is called whenever a plugin is loaded as the
109     plugin might have changed the config values (for instance it might
110     change ckan.site_url) '''
111 
112     config_declaration.setup()
113     config_declaration.make_safe(config)
114     config_declaration.normalize(config)
115 
116     webassets_init()
117 
118     for plugin in p.PluginImplementations(p.IConfigurer):
119         # must do update in place as this does not work:
120         # config = plugin.update_config(config)
121         plugin.update_config(config)
122 
123     # Set whitelisted env vars on config object
124     # This is set up before globals are initialized
125 
126     ckan_db = os.environ.get('CKAN_DB', None)
127     if ckan_db:
128         msg = 'Setting CKAN_DB as an env var is deprecated and will be' \
129             ' removed in a future release. Use CKAN_SQLALCHEMY_URL instead.'
130         log.warn(msg)
131         config['sqlalchemy.url'] = ckan_db
132 
133     for option in CONFIG_FROM_ENV_VARS:
134         from_env = os.environ.get(CONFIG_FROM_ENV_VARS[option], None)
135         if from_env:
136             config[option] = from_env
137 
138     if config.get_value("config.mode") == "strict":
139         _, errors = config_declaration.validate(config)
140         if errors:
141             msg = "\n".join(
142                 "{}: {}".format(key, "; ".join(issues))
143                 for key, issues in errors.items()
144             )
145             raise CkanConfigurationException(msg)
146 
147     root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
148 
149     site_url = config.get_value('ckan.site_url')
150     if not site_url:
151         raise RuntimeError(
152             'ckan.site_url is not configured and it must have a value.'
153             ' Please amend your .ini file.')
154     if not site_url.lower().startswith('http'):
155         raise RuntimeError(
156             'ckan.site_url should be a full URL, including the schema '
157             '(http or https)')
158     # Remove backslash from site_url if present
159     config['ckan.site_url'] = site_url.rstrip('/')
160 
161     display_timezone = config.get_value('ckan.display_timezone')
162     if (display_timezone and
163             display_timezone != 'server' and
164             display_timezone not in pytz.all_timezones):
165         raise CkanConfigurationException(
166             "ckan.display_timezone is not 'server' or a valid timezone"
167         )
168 
169     # Init SOLR settings and check if the schema is compatible
170     # from ckan.lib.search import SolrSettings, check_solr_schema_version
171 
172     # lib.search is imported here as we need the config enabled and parsed
173     search.SolrSettings.init(config.get_value('solr_url'),
174                              config.get_value('solr_user'),
175                              config.get_value('solr_password'))
176     search.check_solr_schema_version()
177 
178     lib_plugins.reset_package_plugins()
179     lib_plugins.register_package_plugins()
180     lib_plugins.reset_group_plugins()
181     lib_plugins.register_group_plugins()
182 
183     # initialise the globals
184     app_globals.app_globals._init()
185 
186     helpers.load_plugin_helpers()
187 
188     # Templates and CSS loading from configuration
189     valid_base_templates_folder_names = ['templates']
190     templates = config.get_value('ckan.base_templates_folder')
191     config['ckan.base_templates_folder'] = templates
192 
193     if templates not in valid_base_templates_folder_names:
194         raise CkanConfigurationException(
195             'You provided an invalid value for ckan.base_templates_folder. '
196             'Possible values are: "templates".'
197         )
198 
199     jinja2_templates_path = os.path.join(root, templates)
200     log.info('Loading templates from %s' % jinja2_templates_path)
201     template_paths = [jinja2_templates_path]
202 
203     extra_template_paths = config.get_value('extra_template_paths')
204     if extra_template_paths:
205         # must be first for them to override defaults
206         template_paths = extra_template_paths.split(',') + template_paths
207     config['computed_template_paths'] = template_paths
208 
209     # Enable pessimistic disconnect handling (added in SQLAlchemy 1.2)
210     # to eliminate database errors due to stale pooled connections
211     config.setdefault('sqlalchemy.pool_pre_ping', True)
212     # Initialize SQLAlchemy
213     engine = sqlalchemy.engine_from_config(config)
214     model.init_model(engine)
215 
216     for plugin in p.PluginImplementations(p.IConfigurable):
217         plugin.configure(config)
218 
219     # clear other caches
220     logic.clear_actions_cache()
221     logic.clear_validators_cache()
222     authz.clear_auth_functions_cache()
223 
224     # Here we create the site user if they are not already in the database
225     try:
226         logic.get_action('get_site_user')({'ignore_auth': True}, None)
227     except (sqlalchemy.exc.ProgrammingError, sqlalchemy.exc.OperationalError):
228         # The database is not yet initialised. It happens in `ckan db init`
229         pass
230 
231     # Close current session and open database connections to ensure a clean
232     # clean environment even if an error occurs later on
233     model.Session.remove()
234     model.Session.bind.dispose()
235
```
--- 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/ckan/config/environment.py b/ckan/config/environment.py
--- a/ckan/config/environment.py
+++ b/ckan/config/environment.py
@@ -227,6 +227,9 @@
     except (sqlalchemy.exc.ProgrammingError, sqlalchemy.exc.OperationalError):
         # The database is not yet initialised. It happens in `ckan db init`
         pass
+    except sqlalchemy.exc.IntegrityError:
+        # Race condition, user already exists.
+        pass
 
     # Close current session and open database connections to ensure a clean
     # clean environment even if an error occurs later on

{"golden_diff": "diff --git a/ckan/config/environment.py b/ckan/config/environment.py\n--- a/ckan/config/environment.py\n+++ b/ckan/config/environment.py\n@@ -227,6 +227,9 @@\n     except (sqlalchemy.exc.ProgrammingError, sqlalchemy.exc.OperationalError):\n         # The database is not yet initialised. It happens in `ckan db init`\n         pass\n+    except sqlalchemy.exc.IntegrityError:\n+        # Race condition, user already exists.\n+        pass\n \n     # Close current session and open database connections to ensure a clean\n     # clean environment even if an error occurs later on\n", "issue": "Intermittent duplicate key errors when creating default sysadmin\n**CKAN version**\r\n\r\nCKAN 2.9.x. Does not appear to affect 2.8.\r\n\r\n**Describe the bug**\r\n\r\nWhen our continuous integration tests initialise a test CKAN 2.9 instance, they sometimes encounter a duplicate key exception when CKAN is attempting to create the 'default' sysadmin account. There does not appear to be any specific pattern to when the errors occur; re-running the build may resolve it, or not. This did not occur on CKAN 2.8.\r\n\r\n**Steps to reproduce**\r\n\r\nOur test scripts run the following CLI commands:\r\n\r\nckan -c /etc/ckan/default/production.ini db clean --yes\r\nckan -c /etc/ckan/default/production.ini db init\r\nckan -c /etc/ckan/default/production.ini comments initdb\r\nckan -c /etc/ckan/default/production.ini comments updatedb\r\nckan -c /etc/ckan/default/production.ini comments init_notifications_db\r\n\r\n**Additional details**\r\nSample failed build:\r\n\r\nhttps://github.com/qld-gov-au/ckanext-ytp-comments/runs/4480610398?check_suite_focus=true\r\n\r\n(Search for \"already exists\" to locate the stack trace)\r\n\r\nNB Although the error actually occurred on that run during a `ckanext-ytp-comments` command, it was not specific to the extension, as shown by an excerpt from the stack trace:\r\n\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/cli/cli.py\", line 102, in _init_ckan_config\r\n        ckan_1                |     ctx.obj = CkanCommand(value)\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/cli/cli.py\", line 52, in __init__\r\n        ckan_1                |     self.app = make_app(self.config)\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/config/middleware/__init__.py\", line 56, in make_app\r\n        ckan_1                |     load_environment(conf)\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/config/environment.py\", line 123, in load_environment\r\n        ckan_1                |     p.load_all()\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/plugins/core.py\", line 161, in load_all\r\n        ckan_1                |     unload_all()\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/plugins/core.py\", line 208, in unload_all\r\n        ckan_1                |     unload(*reversed(_PLUGINS))\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/plugins/core.py\", line 236, in unload\r\n        ckan_1                |     plugins_update()\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/plugins/core.py\", line 153, in plugins_update\r\n        ckan_1                |     environment.update_config()\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/config/environment.py\", line 322, in update_config\r\n        ckan_1                |     logic.get_action('get_site_user')({'ignore_auth': True}, None)\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/logic/__init__.py\", line 477, in wrapped\r\n        ckan_1                |     result = _action(context, data_dict, **kw)\r\n        ckan_1                |   File \"/app/ckan/default/src/ckan/ckan/logic/action/get.py\", line 2398, in get_site_user\r\n        ckan_1                |     model.Session.flush()\n", "before_files": [{"content": "# encoding: utf-8\n\n'''CKAN environment configuration'''\nimport os\nimport logging\nimport warnings\nimport pytz\n\nimport sqlalchemy\n\nimport ckan.model as model\nimport ckan.plugins as p\nimport ckan.lib.plugins as lib_plugins\nimport ckan.lib.helpers as helpers\nimport ckan.lib.app_globals as app_globals\nfrom ckan.lib.redis import is_redis_available\nimport ckan.lib.search as search\nimport ckan.logic as logic\nimport ckan.authz as authz\nfrom ckan.lib.webassets_tools import webassets_init\nfrom ckan.lib.i18n import build_js_translations\n\nfrom ckan.common import config, config_declaration\nfrom ckan.exceptions import CkanConfigurationException\nlog = logging.getLogger(__name__)\n\n# Suppress benign warning 'Unbuilt egg for setuptools'\nwarnings.simplefilter('ignore', UserWarning)\n\n\ndef load_environment(conf):\n    \"\"\"\n    Configure the Pylons environment via the ``pylons.config`` object. This\n    code should only need to be run once.\n    \"\"\"\n    os.environ['CKAN_CONFIG'] = conf['__file__']\n\n    valid_base_public_folder_names = ['public']\n    static_files = conf.get('ckan.base_public_folder', 'public')\n    conf['ckan.base_public_folder'] = static_files\n\n    if static_files not in valid_base_public_folder_names:\n        raise CkanConfigurationException(\n            'You provided an invalid value for ckan.base_public_folder. '\n            'Possible values are: \"public\".'\n        )\n\n    log.info('Loading static files from %s' % static_files)\n\n    # Initialize main CKAN config object\n    config.update(conf)\n\n    # Setup the SQLAlchemy database engine\n    # Suppress a couple of sqlalchemy warnings\n    msgs = ['^Unicode type received non-unicode bind param value',\n            \"^Did not recognize type 'BIGINT' of column 'size'\",\n            \"^Did not recognize type 'tsvector' of column 'search_vector'\"\n            ]\n    for msg in msgs:\n        warnings.filterwarnings('ignore', msg, sqlalchemy.exc.SAWarning)\n\n    # load all CKAN plugins\n    p.load_all()\n\n    # Check Redis availability\n    if not is_redis_available():\n        log.critical('Could not connect to Redis.')\n\n    app_globals.reset()\n\n    # issue #3260: remove idle transaction\n    # Session that was used for getting all config params nor committed,\n    # neither removed and we have idle connection as result\n    model.Session.commit()\n\n    # Build JavaScript translations. Must be done after plugins have\n    # been loaded.\n    build_js_translations()\n\n\n# A mapping of config settings that can be overridden by env vars.\n# Note: Do not remove the following lines, they are used in the docs\n# Start CONFIG_FROM_ENV_VARS\nCONFIG_FROM_ENV_VARS = {\n    'sqlalchemy.url': 'CKAN_SQLALCHEMY_URL',\n    'ckan.datastore.write_url': 'CKAN_DATASTORE_WRITE_URL',\n    'ckan.datastore.read_url': 'CKAN_DATASTORE_READ_URL',\n    'ckan.redis.url': 'CKAN_REDIS_URL',\n    'solr_url': 'CKAN_SOLR_URL',\n    'solr_user': 'CKAN_SOLR_USER',\n    'solr_password': 'CKAN_SOLR_PASSWORD',\n    'ckan.site_id': 'CKAN_SITE_ID',\n    'ckan.site_url': 'CKAN_SITE_URL',\n    'ckan.storage_path': 'CKAN_STORAGE_PATH',\n    'ckan.datapusher.url': 'CKAN_DATAPUSHER_URL',\n    'smtp.server': 'CKAN_SMTP_SERVER',\n    'smtp.starttls': 'CKAN_SMTP_STARTTLS',\n    'smtp.user': 'CKAN_SMTP_USER',\n    'smtp.password': 'CKAN_SMTP_PASSWORD',\n    'smtp.mail_from': 'CKAN_SMTP_MAIL_FROM',\n    'ckan.max_resource_size': 'CKAN_MAX_UPLOAD_SIZE_MB'\n}\n# End CONFIG_FROM_ENV_VARS\n\n\ndef update_config():\n    ''' This code needs to be run when the config is changed to take those\n    changes into account. It is called whenever a plugin is loaded as the\n    plugin might have changed the config values (for instance it might\n    change ckan.site_url) '''\n\n    config_declaration.setup()\n    config_declaration.make_safe(config)\n    config_declaration.normalize(config)\n\n    webassets_init()\n\n    for plugin in p.PluginImplementations(p.IConfigurer):\n        # must do update in place as this does not work:\n        # config = plugin.update_config(config)\n        plugin.update_config(config)\n\n    # Set whitelisted env vars on config object\n    # This is set up before globals are initialized\n\n    ckan_db = os.environ.get('CKAN_DB', None)\n    if ckan_db:\n        msg = 'Setting CKAN_DB as an env var is deprecated and will be' \\\n            ' removed in a future release. Use CKAN_SQLALCHEMY_URL instead.'\n        log.warn(msg)\n        config['sqlalchemy.url'] = ckan_db\n\n    for option in CONFIG_FROM_ENV_VARS:\n        from_env = os.environ.get(CONFIG_FROM_ENV_VARS[option], None)\n        if from_env:\n            config[option] = from_env\n\n    if config.get_value(\"config.mode\") == \"strict\":\n        _, errors = config_declaration.validate(config)\n        if errors:\n            msg = \"\\n\".join(\n                \"{}: {}\".format(key, \"; \".join(issues))\n                for key, issues in errors.items()\n            )\n            raise CkanConfigurationException(msg)\n\n    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n\n    site_url = config.get_value('ckan.site_url')\n    if not site_url:\n        raise RuntimeError(\n            'ckan.site_url is not configured and it must have a value.'\n            ' Please amend your .ini file.')\n    if not site_url.lower().startswith('http'):\n        raise RuntimeError(\n            'ckan.site_url should be a full URL, including the schema '\n            '(http or https)')\n    # Remove backslash from site_url if present\n    config['ckan.site_url'] = site_url.rstrip('/')\n\n    display_timezone = config.get_value('ckan.display_timezone')\n    if (display_timezone and\n            display_timezone != 'server' and\n            display_timezone not in pytz.all_timezones):\n        raise CkanConfigurationException(\n            \"ckan.display_timezone is not 'server' or a valid timezone\"\n        )\n\n    # Init SOLR settings and check if the schema is compatible\n    # from ckan.lib.search import SolrSettings, check_solr_schema_version\n\n    # lib.search is imported here as we need the config enabled and parsed\n    search.SolrSettings.init(config.get_value('solr_url'),\n                             config.get_value('solr_user'),\n                             config.get_value('solr_password'))\n    search.check_solr_schema_version()\n\n    lib_plugins.reset_package_plugins()\n    lib_plugins.register_package_plugins()\n    lib_plugins.reset_group_plugins()\n    lib_plugins.register_group_plugins()\n\n    # initialise the globals\n    app_globals.app_globals._init()\n\n    helpers.load_plugin_helpers()\n\n    # Templates and CSS loading from configuration\n    valid_base_templates_folder_names = ['templates']\n    templates = config.get_value('ckan.base_templates_folder')\n    config['ckan.base_templates_folder'] = templates\n\n    if templates not in valid_base_templates_folder_names:\n        raise CkanConfigurationException(\n            'You provided an invalid value for ckan.base_templates_folder. '\n            'Possible values are: \"templates\".'\n        )\n\n    jinja2_templates_path = os.path.join(root, templates)\n    log.info('Loading templates from %s' % jinja2_templates_path)\n    template_paths = [jinja2_templates_path]\n\n    extra_template_paths = config.get_value('extra_template_paths')\n    if extra_template_paths:\n        # must be first for them to override defaults\n        template_paths = extra_template_paths.split(',') + template_paths\n    config['computed_template_paths'] = template_paths\n\n    # Enable pessimistic disconnect handling (added in SQLAlchemy 1.2)\n    # to eliminate database errors due to stale pooled connections\n    config.setdefault('sqlalchemy.pool_pre_ping', True)\n    # Initialize SQLAlchemy\n    engine = sqlalchemy.engine_from_config(config)\n    model.init_model(engine)\n\n    for plugin in p.PluginImplementations(p.IConfigurable):\n        plugin.configure(config)\n\n    # clear other caches\n    logic.clear_actions_cache()\n    logic.clear_validators_cache()\n    authz.clear_auth_functions_cache()\n\n    # Here we create the site user if they are not already in the database\n    try:\n        logic.get_action('get_site_user')({'ignore_auth': True}, None)\n    except (sqlalchemy.exc.ProgrammingError, sqlalchemy.exc.OperationalError):\n        # The database is not yet initialised. It happens in `ckan db init`\n        pass\n\n    # Close current session and open database connections to ensure a clean\n    # clean environment even if an error occurs later on\n    model.Session.remove()\n    model.Session.bind.dispose()\n", "path": "ckan/config/environment.py"}], "after_files": [{"content": "# encoding: utf-8\n\n'''CKAN environment configuration'''\nimport os\nimport logging\nimport warnings\nimport pytz\n\nimport sqlalchemy\n\nimport ckan.model as model\nimport ckan.plugins as p\nimport ckan.lib.plugins as lib_plugins\nimport ckan.lib.helpers as helpers\nimport ckan.lib.app_globals as app_globals\nfrom ckan.lib.redis import is_redis_available\nimport ckan.lib.search as search\nimport ckan.logic as logic\nimport ckan.authz as authz\nfrom ckan.lib.webassets_tools import webassets_init\nfrom ckan.lib.i18n import build_js_translations\n\nfrom ckan.common import config, config_declaration\nfrom ckan.exceptions import CkanConfigurationException\nlog = logging.getLogger(__name__)\n\n# Suppress benign warning 'Unbuilt egg for setuptools'\nwarnings.simplefilter('ignore', UserWarning)\n\n\ndef load_environment(conf):\n    \"\"\"\n    Configure the Pylons environment via the ``pylons.config`` object. This\n    code should only need to be run once.\n    \"\"\"\n    os.environ['CKAN_CONFIG'] = conf['__file__']\n\n    valid_base_public_folder_names = ['public']\n    static_files = conf.get('ckan.base_public_folder', 'public')\n    conf['ckan.base_public_folder'] = static_files\n\n    if static_files not in valid_base_public_folder_names:\n        raise CkanConfigurationException(\n            'You provided an invalid value for ckan.base_public_folder. '\n            'Possible values are: \"public\".'\n        )\n\n    log.info('Loading static files from %s' % static_files)\n\n    # Initialize main CKAN config object\n    config.update(conf)\n\n    # Setup the SQLAlchemy database engine\n    # Suppress a couple of sqlalchemy warnings\n    msgs = ['^Unicode type received non-unicode bind param value',\n            \"^Did not recognize type 'BIGINT' of column 'size'\",\n            \"^Did not recognize type 'tsvector' of column 'search_vector'\"\n            ]\n    for msg in msgs:\n        warnings.filterwarnings('ignore', msg, sqlalchemy.exc.SAWarning)\n\n    # load all CKAN plugins\n    p.load_all()\n\n    # Check Redis availability\n    if not is_redis_available():\n        log.critical('Could not connect to Redis.')\n\n    app_globals.reset()\n\n    # issue #3260: remove idle transaction\n    # Session that was used for getting all config params nor committed,\n    # neither removed and we have idle connection as result\n    model.Session.commit()\n\n    # Build JavaScript translations. Must be done after plugins have\n    # been loaded.\n    build_js_translations()\n\n\n# A mapping of config settings that can be overridden by env vars.\n# Note: Do not remove the following lines, they are used in the docs\n# Start CONFIG_FROM_ENV_VARS\nCONFIG_FROM_ENV_VARS = {\n    'sqlalchemy.url': 'CKAN_SQLALCHEMY_URL',\n    'ckan.datastore.write_url': 'CKAN_DATASTORE_WRITE_URL',\n    'ckan.datastore.read_url': 'CKAN_DATASTORE_READ_URL',\n    'ckan.redis.url': 'CKAN_REDIS_URL',\n    'solr_url': 'CKAN_SOLR_URL',\n    'solr_user': 'CKAN_SOLR_USER',\n    'solr_password': 'CKAN_SOLR_PASSWORD',\n    'ckan.site_id': 'CKAN_SITE_ID',\n    'ckan.site_url': 'CKAN_SITE_URL',\n    'ckan.storage_path': 'CKAN_STORAGE_PATH',\n    'ckan.datapusher.url': 'CKAN_DATAPUSHER_URL',\n    'smtp.server': 'CKAN_SMTP_SERVER',\n    'smtp.starttls': 'CKAN_SMTP_STARTTLS',\n    'smtp.user': 'CKAN_SMTP_USER',\n    'smtp.password': 'CKAN_SMTP_PASSWORD',\n    'smtp.mail_from': 'CKAN_SMTP_MAIL_FROM',\n    'ckan.max_resource_size': 'CKAN_MAX_UPLOAD_SIZE_MB'\n}\n# End CONFIG_FROM_ENV_VARS\n\n\ndef update_config():\n    ''' This code needs to be run when the config is changed to take those\n    changes into account. It is called whenever a plugin is loaded as the\n    plugin might have changed the config values (for instance it might\n    change ckan.site_url) '''\n\n    config_declaration.setup()\n    config_declaration.make_safe(config)\n    config_declaration.normalize(config)\n\n    webassets_init()\n\n    for plugin in p.PluginImplementations(p.IConfigurer):\n        # must do update in place as this does not work:\n        # config = plugin.update_config(config)\n        plugin.update_config(config)\n\n    # Set whitelisted env vars on config object\n    # This is set up before globals are initialized\n\n    ckan_db = os.environ.get('CKAN_DB', None)\n    if ckan_db:\n        msg = 'Setting CKAN_DB as an env var is deprecated and will be' \\\n            ' removed in a future release. Use CKAN_SQLALCHEMY_URL instead.'\n        log.warn(msg)\n        config['sqlalchemy.url'] = ckan_db\n\n    for option in CONFIG_FROM_ENV_VARS:\n        from_env = os.environ.get(CONFIG_FROM_ENV_VARS[option], None)\n        if from_env:\n            config[option] = from_env\n\n    if config.get_value(\"config.mode\") == \"strict\":\n        _, errors = config_declaration.validate(config)\n        if errors:\n            msg = \"\\n\".join(\n                \"{}: {}\".format(key, \"; \".join(issues))\n                for key, issues in errors.items()\n            )\n            raise CkanConfigurationException(msg)\n\n    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n\n    site_url = config.get_value('ckan.site_url')\n    if not site_url:\n        raise RuntimeError(\n            'ckan.site_url is not configured and it must have a value.'\n            ' Please amend your .ini file.')\n    if not site_url.lower().startswith('http'):\n        raise RuntimeError(\n            'ckan.site_url should be a full URL, including the schema '\n            '(http or https)')\n    # Remove backslash from site_url if present\n    config['ckan.site_url'] = site_url.rstrip('/')\n\n    display_timezone = config.get_value('ckan.display_timezone')\n    if (display_timezone and\n            display_timezone != 'server' and\n            display_timezone not in pytz.all_timezones):\n        raise CkanConfigurationException(\n            \"ckan.display_timezone is not 'server' or a valid timezone\"\n        )\n\n    # Init SOLR settings and check if the schema is compatible\n    # from ckan.lib.search import SolrSettings, check_solr_schema_version\n\n    # lib.search is imported here as we need the config enabled and parsed\n    search.SolrSettings.init(config.get_value('solr_url'),\n                             config.get_value('solr_user'),\n                             config.get_value('solr_password'))\n    search.check_solr_schema_version()\n\n    lib_plugins.reset_package_plugins()\n    lib_plugins.register_package_plugins()\n    lib_plugins.reset_group_plugins()\n    lib_plugins.register_group_plugins()\n\n    # initialise the globals\n    app_globals.app_globals._init()\n\n    helpers.load_plugin_helpers()\n\n    # Templates and CSS loading from configuration\n    valid_base_templates_folder_names = ['templates']\n    templates = config.get_value('ckan.base_templates_folder')\n    config['ckan.base_templates_folder'] = templates\n\n    if templates not in valid_base_templates_folder_names:\n        raise CkanConfigurationException(\n            'You provided an invalid value for ckan.base_templates_folder. '\n            'Possible values are: \"templates\".'\n        )\n\n    jinja2_templates_path = os.path.join(root, templates)\n    log.info('Loading templates from %s' % jinja2_templates_path)\n    template_paths = [jinja2_templates_path]\n\n    extra_template_paths = config.get_value('extra_template_paths')\n    if extra_template_paths:\n        # must be first for them to override defaults\n        template_paths = extra_template_paths.split(',') + template_paths\n    config['computed_template_paths'] = template_paths\n\n    # Enable pessimistic disconnect handling (added in SQLAlchemy 1.2)\n    # to eliminate database errors due to stale pooled connections\n    config.setdefault('sqlalchemy.pool_pre_ping', True)\n    # Initialize SQLAlchemy\n    engine = sqlalchemy.engine_from_config(config)\n    model.init_model(engine)\n\n    for plugin in p.PluginImplementations(p.IConfigurable):\n        plugin.configure(config)\n\n    # clear other caches\n    logic.clear_actions_cache()\n    logic.clear_validators_cache()\n    authz.clear_auth_functions_cache()\n\n    # Here we create the site user if they are not already in the database\n    try:\n        logic.get_action('get_site_user')({'ignore_auth': True}, None)\n    except (sqlalchemy.exc.ProgrammingError, sqlalchemy.exc.OperationalError):\n        # The database is not yet initialised. It happens in `ckan db init`\n        pass\n    except sqlalchemy.exc.IntegrityError:\n        # Race condition, user already exists.\n        pass\n\n    # Close current session and open database connections to ensure a clean\n    # clean environment even if an error occurs later on\n    model.Session.remove()\n    model.Session.bind.dispose()\n", "path": "ckan/config/environment.py"}]}