Jak zdobyć Registry ().ustawienia podczas uruchamiania aplikacji Pyramid?

Jestem przyzwyczajony do tworzenia aplikacji internetowych na Django i gunicorn.

W przypadku Django, dowolne moduły aplikacji w aplikacji Django mogą uzyskać ustawienia deployment poprzez django.conf.ustawienia . The "settings.py" jest napisany w Pythonie, dzięki czemu dowolne ustawienia i wstępne przetwarzanie mogą być definiowane dynamicznie .

W przypadku gunicorn, ma trzy miejsca konfiguracji w kolejności pierwszeństwa, a jedna instancja klasy rejestru ustawień łączy te.(Ale zazwyczaj te ustawienia są używane tylko dla gunicorn Nie aplikacji.)

  1. parametry wiersza poleceń.
  2. plik konfiguracyjny. (jak Django, napisane w Python, który może mieć dowolne dowolne ustawienia dynamicznie .)
  3. Ustawienia aplikacji Paster.

W przypadku Pyramid, zgodnie z dokumentacją Pyramid, ustawienia rozmieszczenia można zazwyczaj umieścić w pyramid.rejestr.Registry ().ustawienia . Ale wydaje się być dostępne tylko wtedy, gdy piramida.router.Istnieje instancja Router () . To jest piramida.threadlocal.get_current_registry().ustawienia nie zwracają żadnych, podczas uruchamiania aplikacji "main.py".

Na przykład zwykle definiuję logikę biznesową w modułach modelu SQLAlchemy, która wymaga następujących ustawień wdrażania.

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)

Ale "settings ['external_api_endpoint'] "wyświetla wyjątek TypeError, ponieważ "settings" to None.

Myślałem, że dwa rozwiązania.

  • Define a callable which accepts" config " argument in "models.py" i "main.py / align = "left" / Instancja Configurator ().

    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
    
  • Lub, umieścić pusty moduł "app/settings.py", i umieścić w nim później.

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

Oba i inne rozwiązania spełniają wymagania, ale czuję się kłopotliwy. To, czego chcę, to następstwa.

  • Rozwój.ini

    Definiuje szorstki ustawienia, ponieważ rozwój.ini może mieć tylko stałe typu string.

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

    Definiuje ustawienia szczegółów w oparciu o rozwój.ini, beacause można ustawić dowolne zmienne(typy).

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

Następnie inne moduły mogą uzyskać dowolne ustawienia wdrażania poprzez " Importuj myapp.ustawienia". Lub, jeśli Registry().ustawienia są lepsze niż "settings.py", * * ustawienia kwargs i "settings.py" mogą być łączone i rejestrowane w Registry ().ustawienia podczas "main.py" proces uruchamiania.

W każdym razie, jak uzyskać dictionay ustawienia podczas uruchamiania ? Lub, Pyramid delikatnie zmusza nas do umieszczenia każdego kodu, który wymaga ustawień wdrożenia w" views " wywołania, które mogą uzyskać słownik ustawień w dowolnym momencie poprzez żądanie.rejestr.ustawienia ?


EDIT

Dzięki, Michael i Chris.

W końcu rozumiem, dlaczego Pyramid używa zmiennych threadlocal( registry i request), w konkretny obiekt rejestru dla więcej niż jednej aplikacji piramidy.

Moim zdaniem jednak ustawienia wdrażania zwykle wpływają na logikę biznesową, która może definiować pewne elementy specyficzne dla aplikacji. Te logiki są zwykle umieszczane w jednym lub kilku modułach Pythona, które mogą być inne niż "app / init.py" lub "app/views.py", które mogą łatwo uzyskać dostęp do config () lub Registry (). Te moduły Pythona są zwykle "globalne" na poziomie procesów Pythona.

To znaczy, nawet gdy więcej niż jeden Aplikacje Pyramid współistnieją, pomimo własnych zmiennych threadlocal, muszą współdzielić te "globalne" Moduły Pythona, które mogą zawierać specyficzne dla aplikacji elementy na poziomie procesu Pythona.

Z powodu, każdy z tych modułów może mieć wywołanie "initialize ()", które jest wywoływane z konfiguratorem() przez aplikację "main" wywoływalną, lub przechodzenie obiektu Registory() lub Request () przez tak długie serie wywołań funkcji może spełniać zwykłe wymagania. Ale chyba początkujący piramidy (jak ja) lub programiści, którzy mają "dużą aplikację lub tak wiele ustawień" mogą czuć się kłopotliwi, chociaż jest to konstrukcja piramidy.

Tak myślę, Registry ().ustawienia powinny mieć tylko rzeczywiste zmienne "thread-local" i nie powinny mieć normalnych ustawień logiki biznesowej. Odpowiedzialność za segregację wielu modułów specyficznych dla aplikacji, klas, zmiennych wywołujących itp. powinny być podjęte przez dewelopera. Od teraz, z mojego punktu widzenia, przyjmę odpowiedź Chrisa. Lub w" main " callable, do "execfile('settings.py', settings, settings) "i umieścić go w jakiejś "globalnej" przestrzeni.

Author: takaomag, 2011-06-28

3 answers

Kolejna opcja, jeśli lubisz konfigurację globalną za pomocą Pythona, Utwórz settings.py plik. Jeśli potrzebuje wartości z pliku ini, przeanalizuj plik ini i wyciągnij je (w zakresie modułu, więc działa w czasie importu):

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 'to nazwa pliku ini (poprzedzona' config:'). "myapp" to nazwa sekcji w pliku konfiguracyjnym reprezentującej Twoją aplikację(np. [app: myapp]). "relative_to" to nazwa katalogu, w którym można znaleźć plik konfiguracyjny.

 16
Author: Chris McDonough,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-29 08:29:33

Używany przeze mnie wzorzec przekazuje Configurator do modułów, które muszą zostać zainicjowane. Pyramid nie używa żadnych zmiennych globalnych, ponieważ celem projektu jest możliwość uruchamiania wielu instancji Pyramid w tym samym procesie. Threadlocals są globalne, ale są lokalne dla bieżącego żądania, więc różne aplikacje piramidy mogą do nich wysyłać w tym samym czasie z różnych wątków.

Mając to na uwadze, jeśli chcesz mieć globalny słownik ustawień, musisz sam się tym zająć. Możesz nawet sam wcisnąć rejestr do menedżera threadlocal, dzwoniąc config.begin().

Myślę, że najważniejsze jest to, że nie powinieneś wywoływać get_current_registry() na poziomie modułu, ponieważ w momencie importowania nie masz gwarancji, że threadlocal zostaną zainicjowane, jednak w Twojej init_model() funkcji, jeśli wywołasz get_current_registry(), będzie dobrze, jeśli wcześniej wywołałeś config.begin().

Przepraszam, że to trochę zawiłe, ale to częste pytanie, a najlepszą odpowiedzią jest: przekaż konfigurator do podmodułów, które go potrzebują i pozwól im dodawać rzeczy do obiektów rejestru / ustawień do późniejszego użycia.

 13
Author: Michael Merickel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-29 08:06:38

Pyramid używa statycznej konfiguracji przez PasteDeploy, w przeciwieństwie do Django. [Edytuj] część jest dobrym rozwiązaniem, myślę, że społeczność piramidy powinna rozważyć takie użycie.

 1
Author: nyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-05 12:03:52