title: How to get Registry().settings during Pyramid app startup time?
body: <p>I am used to develop web applications on Django and gunicorn.</p>
  
  <p>In case of Django, any application modules in a Django application can get deployment settings through <em>django.conf.settings</em>. The "settings.py" is written in Python, so that any arbitrary settings and pre-processing can be defined <strong>dynamically</strong>.</p>
  
  <p>In case of gunicorn, it has three configuration places in order of precedence, and one settings registry class instance combines those.(But usually these settings are used only for gunicorn not application.)</p>
  
  <ol>
  <li>Command line parameters.</li>
  <li>Configuration file. (like Django, written in
  Python which can have any arbitrary
  settings <strong>dynamically</strong>.)</li>
  <li>Paster application settings.</li>
  </ol>
  
  <p>In case of Pyramid, according to Pyramid documentation, deployment settings may be usually put into <em>pyramid.registry.Registry().settings</em>. But it seems to be accessed only when a <em>pyramid.router.Router()</em> instances exists.
  That is pyramid.threadlocal.get_current_registry().settings returns None, during the startup process in an application "main.py".</p>
  
  <p>For example, I usually define some business logic in SQLAlchemy model modules, which requires deployment settings as follows.</p>
  
  <p><code>myapp/models.py</code></p>
  
  <pre><code>from sqlalchemy import Table, Column, Types
  from sqlalchemy.orm import mapper
  from pyramid.threadlocal import get_current_registry
  from myapp.db import session, metadata
  
  settings = get_current_registry().settings
  
  mytable = Table('mytable', metadata,
      Column('id', Types.INTEGER, primary_key=True,)
      (other columns)...
  )
  
  class MyModel(object):
      query = session.query_property()
      external_api_endpoint = settings['external_api_uri']
      timezone = settings['timezone']
  
      def get_api_result(self):
          (interact with external api ...)
  
  mapper(MyModel, mytable)
  </code></pre>
  
  <p>But, "settings['external_api_endpoint']" raises a TypeError exception because the "settings" is None.</p>
  
  <p>I thought two solutions.</p>
  
  <ul>
  <li><p>Define a callable which accepts "config" argument in "models.py" and "main.py" calls it with a
  Configurator() instance.</p>
  
  <p><code>myapp/models.py</code></p>
  
  <pre><code>from sqlalchemy import Table, Column, Types
  from sqlalchemy.orm import mapper
  from myapp.db import session, metadata
  
  _g = globals()
  def initialize(config):
      settings = config.get_settings()
      mytable = Table('mytable', metadata,
          Column('id', Types.INTEGER, rimary_key = True,)
          (other columns ...)
      )
      class MyModel(object):
          query = session.query_property()
          external_api_endpoint = settings['external_api_endpoint']
  
          def get_api_result(self):
              (interact with external api)...
  
      mapper(MyModel, mytable)
      _g['MyModel'] = MyModel
      _g['mytable'] = mytable
  </code></pre></li>
  <li><p>Or, put an empty module "app/settings.py", and put setting into it later.</p>
  
  <p><code>myapp/__init__.py</code></p>
  
  <pre><code>from pyramid.config import Configurator
  from .resources import RootResource
  
  def main(global_config, **settings):
      config = Configurator(
          settings = settings,
          root_factory = RootResource,
      )
      import myapp.settings
      myapp.setting.settings = config.get_settings()
      (other configurations ...)
      return config.make_wsgi_app()
  </code></pre></li>
  </ul>
  
  <p>Both and other solutions meet the requirements, but I feel troublesome. What I want is the followings.</p>
  
  <ul>
  <li><p>development.ini</p>
  
  <p>defines rough settings because development.ini can have only <strong>string</strong> type constants.</p>
  
  <pre><code>[app:myapp]
  use = egg:myapp
  env = dev0
  api_signature = xxxxxx
  </code></pre></li>
  <li><p>myapp/settings.py</p>
  
  <p>defines detail settings based on development.ini, beacause any arbitrary variables(types) can be set.</p>
  
  <pre><code>import datetime, urllib
  from pytz import timezone
  from pyramid.threadlocal import get_current_registry
  
  pyramid_settings = get_current_registry().settings
  
  if pyramid_settings['env'] == 'production':
      api_endpoint_uri = 'http://api.external.com/?{0}'
      timezone = timezone('US/Eastern')
  elif pyramid_settings['env'] == 'dev0':
      api_endpoint_uri = 'http://sandbox0.external.com/?{0}'
      timezone = timezone('Australia/Sydney')
  elif pyramid_settings['env'] == 'dev1':
      api_endpoint_uri = 'http://sandbox1.external.com/?{0}'
      timezone = timezone('JP/Tokyo')
  api_endpoint_uri = api_endpoint_uri.format(urllib.urlencode({'signature':pyramid_settings['api_signature']}))
  </code></pre></li>
  </ul>
  
  <p>Then, other modules can get arbitrary deployment settings through "import myapp.settings".
  Or, if Registry().settings is preferable than "settings.py", **settings kwargs and "settings.py" may be combined and registered into Registry().settings during "main.py" startup process.</p>
  
  <p>Anyway, how to get the settings dictionay during startup time ? Or, Pyramid gently forces us to put every code which requires deployment settings in "views" callables which can get settings dictionary anytime through <em>request.registry.settings</em> ?</p>
  
  <hr>
  
  <p><strong>EDIT</strong></p>
  
  <p>Thanks, Michael and Chris.</p>
  
  <p>I at last understand why Pyramid uses threadlocal variables(registry and request), in particular registry object for more than one Pyramid applications.</p>
  
  <p>In my opinion, however, deployment settings usually affect business logics that may define application-specific somethings. Those logics are usually put in one or more Python modules that may be other than "app/<strong>init</strong>.py" or "app/views.py" that can easily get access to Config() or Registry(). Those Python modules are normally "global" at Python process level.</p>
  
  <p>That is, even when more than one Pyramid applications coexist, despite their own threadlocal variables, they have to share those "global" Python modules that may contain applicatin-specific somethings at Python process level.</p>
  
  <p>Of cause, every those modules can have "initialize()" callalbe which is called with a Configurator() by the application "main" callable, or passing Registory() or Request() object through so long series of function calls can meet usual requirements. But, I guess Pyramid beginers (like me) or developers who has "large application or so many settings" may feel troublesome, although that is Pyramid design.</p>
  
  <p>So, I think, Registry().settings should have only real "thread-local" variables, and should not have normal business-logic settings. Responsibility for segregation of multiple application-specific module, classes, callables variables etc. should be taken by developer.
  As of now, from my viewpoint, I will take Chris's answer. Or in "main" callable, do "execfile('settings.py', settings, settings)" and put it in some "global" space.</p>