2011-06-28 21 views
21

Estoy acostumbrado a desarrollar aplicaciones web en Django y gunicornio.¿Cómo obtener la configuración del Registro() durante el tiempo de inicio de la aplicación Pyramid?

En el caso de Django, cualquier módulo de aplicación en una aplicación Django puede obtener configuraciones de implementación a través de django.conf.settings. El "settings.py" está escrito en Python, por lo que se puede definir cualquier configuración arbitraria y preprocesamiento dinámicamente.

En caso de gunicorn, tiene tres lugares de configuración en orden de precedencia, y de una configuración instancia de clase de registro combina esos. (Pero por lo general estos valores sólo se utilizan para gunicorn no aplicación.)

  1. línea de comandos parámetros.
  2. Archivo de configuración. (como Django, escrito en Python que puede tener cualquier configuración arbitraria dinámicamente.)
  3. Ajustes de la aplicación de Paster.

En caso de pirámide, según la documentación de la pirámide, la configuración de implementación puede ser por lo general ponen en pyramid.registry.Registry(). configuración. Pero parece que se accede solo cuando existe una pyramid.router.Router() instancias. Eso es pyramid.threadlocal.get_current_registry(). Settings devuelve None, durante el proceso de inicio en una aplicación "main.py".

Por ejemplo, generalmente defino cierta lógica comercial en los módulos de modelo SQLAlchemy, que requiere la configuración de implementación de la siguiente manera.

myapp/models.py

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) 

Pero, "los ajustes [ 'external_api_endpoint']" plantea una excepción TypeError debido a la "configuración" no es.

Pensé dos soluciones.

  • definir un exigible, que acepta el argumento "config" en "models.py" y "main.py" lo llama con una instancia configurador().

    myapp/models.py

    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 
    
  • o, dicho de un módulo vacío "app/settings.py", y poner la configuración en él más tarde.

    myapp/__init__.py

    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() 
    

Tanto y otras soluciones cumplen con los requisitos, pero me siento molesto. Lo que quiero es lo siguiente.

  • development.ini

    define la configuración en bruto al desarrollo.ini solo puede tener string tipo de constantes.

    [app:myapp] 
    use = egg:myapp 
    env = dev0 
    api_signature = xxxxxx 
    
  • miaplicacion/settings.py

    define la configuración detalle basándose en development.ini, Beacause cualesquiera variables arbitrarias (tipos) se puede ajustar.

    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']})) 
    

Luego, otros módulos puede obtener la configuración de implementación arbitraria a través de "importación" myapp.settings. O, si la configuración del Registro(). Es preferible a "settings.py", ** las configuraciones kwargs y "settings.py" pueden combinarse y registrarse en la configuración del Registro() durante el proceso de inicio "main.py".

De todos modos, ¿cómo obtener la configuración dictionay durante el tiempo de inicio? O bien, Pyramid nos obliga a colocar todos los códigos que requieren configuración de implementación en callables de "vistas" que pueden obtener el diccionario de configuración en cualquier momento a través de request.registry.settings?


EDITAR

Gracias, Michael y Chris.

Finalmente, entiendo por qué Pyramid usa variables threadlocal (registro y solicitud), en particular objeto de registro para más de una aplicación Pyramid.

En mi opinión, sin embargo, la configuración de implementación generalmente afecta las lógicas comerciales que pueden definir algunas cosas específicas de la aplicación. Esas lógicas se suelen incluir en uno o más módulos de Python que pueden ser distintos de "app/init .py" o "app/views.py" que pueden acceder fácilmente a Config() o Registry(). Esos módulos de Python son normalmente "globales" en el nivel de proceso de Python.

Es decir, incluso cuando más de una aplicación Pyramid coexisten, a pesar de sus propias variables locales, deben compartir esos módulos "globales" de Python que pueden contener aplicaciones específicas en el nivel de proceso de Python.

De causa, cada uno de esos módulos puede tener "initialize()" callalbe que se llama con un Configurator() por la aplicación "principal" invocable, o pasando el objeto Registory() o Request() a través de series de funciones tan largas las llamadas pueden cumplir con los requisitos habituales. Pero, supongo que los principiantes de Pyramid (como yo) o los desarrolladores que tienen "grandes aplicaciones o tantos ajustes" pueden sentirse molestos, aunque ese sea el diseño de Pyramid.

Por lo tanto, creo que la configuración del Registro() debe tener solo variables reales "thread-local" y no debe tener una configuración lógica de negocios normal. La responsabilidad por la segregación de múltiples módulos específicos de la aplicación, clases, variables callables, etc. debe ser tomada por el desarrollador. A partir de ahora, desde mi punto de vista, responderé a la respuesta de Chris. O en "principal" invocable, haga "execfile ('settings.py', settings, settings)" y póngalo en algún espacio "global".

Respuesta

16

Otra opción, si disfruta de la configuración global a través de Python, cree un archivo settings.py. Si se necesita valores desde el archivo ini, analizar el archivo ini y agarrarlos a cabo (en el ámbito de módulo, para que se ejecute en el tiempo de importación):

from paste.deploy.loadwsgi import appconfig 
config = appconfig('config:development.ini', 'myapp', relative_to='.') 

if config['env'] == 'production': 
    api_endpoint_uri = 'http://api.external.com/?{0}' 
    timezone = timezone('US/Eastern') 
# .. and so on ... 

'config: development.ini' es el nombre de la ini archivo (prefijado con 'config:'). 'myapp' es el nombre de la sección en el archivo de configuración que representa su aplicación (por ejemplo, [aplicación: myapp]). "relative_to" es el nombre del directorio en el que se puede encontrar el archivo de configuración.

+0

¡Gracias! Tomo su solución. La razón se describe más arriba en la parte "EDITAR". (Permítame editarla por descripción larga) – takaomag

13

El patrón que uso es pasar el Configurator a los módulos que deben inicializarse. Pyramid no usa ninguna variable global porque un objetivo de diseño es poder ejecutar varias instancias de Pyramid en el mismo proceso. Los threadlocals son globales, pero son locales a la solicitud actual, por lo que diferentes aplicaciones de Pyramid pueden presionar al mismo tiempo desde diferentes subprocesos.

Con esto en mente, si desea un diccionario de configuraciones globales, tendrá que encargarse de eso usted mismo. Incluso puede insertar el registro en el administrador de threadlocal llamando al config.begin().

creo que la cosa importante para llevar aquí es que usted no debe estar llamando get_current_registry() a nivel de módulo, porque en el momento de la importación no está realmente garantizado que las threadlocals se inicializan, sin embargo, en su función de init_model() si llama al get_current_registry(), estaría bien si anteriormente llamó al config.begin().

sentimos esto es un poco complicado, pero es una pregunta común y la mejor respuesta es: pasar el configurador de sus submódulos que lo necesitan y les permiten añadir cosas para el registro/configuración de objetos para su uso posterior.

+0

Gracias por su respuesta. Desde mi punto de vista, la respuesta de Chris es preferible. El motivo se describe más arriba en la parte "EDITAR". (Permitirme editar debido a la descripción larga. – takaomag

+0

¿Podría explicar el paso del Configurador a los módulos un poco más? ¿Cómo lo pasaría a mis modelos.py? – GhotiPhud

+3

La forma recomendada de extienda las aplicaciones de Pyramid a través de la maquinaria 'config.include' que invocará un método externo y le pasará el objeto de configuración. Esta es una excelente manera de incorporar todos sus módulos y permitirles configurarlos en el momento del inicio. –

1

Pyramid utiliza la configuración estática mediante PasteDeploy, a diferencia de Django. Su parte [EDIT] es una buena solución, creo que la comunidad de Pyramid debería considerar tal uso.

Cuestiones relacionadas