Подтвердить что ты не робот

Как получить настройки реестра() во время запуска приложения Pyramid?

Я использую для разработки веб-приложений на Django и gunicorn.

В случае Django любые прикладные модули в приложении Django могут получить настройки развертывания через django.conf.settings. "Settings.py" написан на Python, так что любые произвольные настройки и предварительная обработка могут быть определены динамически.

В случае с пушкой, у него есть три места конфигурации в порядке приоритета, и один экземпляр класса реестра объединяет их. (Но обычно эти настройки используются только для несобственного применения gunicorn.)

  • Параметры командной строки.
  • Конфигурационный файл. (например, Django, написанный Python, который может иметь любые произвольные настройки динамически.)
  • Настройки приложения Paster.

В случае с Pyramid, согласно документации Pyramid, параметры развертывания обычно можно поместить в настройки pyramid.registry.Registry(). Но, похоже, он доступен только тогда, когда существуют экземпляры pyramid.router.Router(). Это pyramid.threadlocal.get_current_registry(). Settings возвращает None во время процесса запуска в приложении "main.py" .

Например, я обычно определяю некоторую бизнес-логику в модулях модели SQLAlchemy, для чего требуются настройки развертывания следующим образом.

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)

Но "settings ['external_api_endpoint'] вызывает исключение TypeError, потому что" настройки "-" Нет ".

Я думал о двух решениях.

  • Определите вызываемый, который принимает аргумент "config" в "models.py" и "main.py" , вызывает его с помощью Экземпляр 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
    
  • Или, поместите пустой модуль "app/settings.py" и поместите в него настройки позже.

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

Оба и другие решения отвечают требованиям, но я чувствую себя хлопотно. Я хочу, чтобы следующие.

  • development.ini

    определяет грубые настройки, так как для development.ini могут быть только константы string.

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

    определяет подробные настройки на основе development.ini, поскольку любые произвольные переменные (типы) могут быть установлены.

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

Затем другие модули могут получить произвольные параметры развертывания через "import myapp.settings". Или, если настройки Registry() предпочтительны, чем "settings.py", ** настройки kwargs и "settings.py" могут быть объединены и зарегистрированы в настройках Registry() во время запуска "main.py" .

Во всяком случае, как получить настройки dictionay во время запуска? Или, Pyramid мягко заставляет нас помещать каждый код, который требует настроек развертывания в "обратных" вызовах, которые могут получить словарь настроек в любое время через request.registry.settings?


ИЗМЕНИТЬ

Спасибо, Майкл и Крис.

Наконец-то я понимаю, почему Pyramid использует переменные threadlocal (реестр и запрос), в частности объект реестра для более чем одного приложения Pyramid.

Однако, на мой взгляд, параметры развертывания обычно влияют на бизнес-логику, которая может определять специфические для приложения проблемы. Эти логики обычно помещаются в один или несколько модулей Python, которые могут быть отличными от "app/ init.py" или "app/views.py", которые могут легко получить доступ к Config() или Registry (). Эти модули Python обычно являются "глобальными" на уровне процесса Python.

То есть, даже если более одного приложения Pyramid сосуществуют, несмотря на собственные переменные потока, они должны делиться этими "глобальными" модулями Python, которые могут содержать специфические для приложения значения на уровне процесса Python.

Из-за причин, каждый из этих модулей может иметь "initialize()" callalbe, который вызывается с помощью Configurator() приложением "main", вызываемым или передающим объект Registory() или Request() через столь длинные серии вызовов функций могут соответствовать обычным требованиям. Но я думаю, что начинающие пирамиды (например, я) или разработчики, у которых есть "большое приложение или так много настроек", могут чувствовать себя хлопотно, хотя это и есть дизайн Pyramid.

Итак, я думаю, что Registry(). настройки должны иметь только реальные "поточно-локальные" переменные и не должны иметь обычных параметров бизнес-логики. Разработчик должен взять на себя ответственность за сегрегацию нескольких модулей, классов, переменных вызовов и т.д. На данный момент, с моей точки зрения, я отвечу Крису. Или в "main" callable, выполните "execfile (" settings.py ", настройки, настройки)" и поместите его в какое-то "глобальное" пространство.

4b9b3361

Ответ 1

Другой вариант, если вам нравится глобальная настройка через Python, создайте файл settings.py. Если ему нужны значения из ini файла, проанализируйте ini файл и вытащите его (в области модуля, поэтому он запускается во время импорта):

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' - это имя файла ini (с префиксом 'config:'). "myapp" - это имя раздела в файле конфигурации, представляющем ваше приложение (например, [app: myapp]). "relative_to" - это имя каталога, в котором можно найти файл конфигурации.

Ответ 2

Я использую шаблон, чтобы передать Configurator в модули, которые необходимо инициализировать. Pyramid не использует глобальные переменные, потому что целью дизайна является возможность запуска нескольких экземпляров Pyramid в том же процессе. Поля threadlocals являются глобальными, но они локальны для текущего запроса, поэтому различные приложения Pyramid могут одновременно нажимать на них из разных потоков.

С учетом этого, если вам нужен словарь глобальных настроек, вам придется позаботиться об этом самостоятельно. Вы даже можете нажать реестр на диспетчер threadlocal самостоятельно, вызвав config.begin().

Я думаю, что главная вещь, которую нужно убрать здесь, - это то, что вы не должны называть get_current_registry() на уровне модуля, потому что во время импорта вам не гарантируется инициализация threadlocals, однако в вашем init_model(), если вы вызываете get_current_registry(), вам будет хорошо, если вы ранее называли config.begin().

Извините, это немного запутанно, но общий вопрос и лучший ответ: передать конфигуратор вашим подмодулям, которые в нем нуждаются, и позволить им добавлять материал в объекты реестра/настроек для использования позже.

Ответ 3

Pyramid использует статическую конфигурацию PasteDeploy, в отличие от Django. Ваша [EDIT] часть - хорошее решение, я думаю, что сообщество Pyramid должно рассмотреть такое использование.