CONTEXT¶
Propan хранит контекс приложения и каждого запроса в глобальном контексе, доступ к которому вы можете получить с помощью специального класса Context.
1 2 3 4 5 | |
Существующие поля¶
Context уже содержит некоторые глобальные объекты, к которым вы всегда можете получить доступ:
- app - объект
PropanAppвашего приложения - broker - текущий брокер
- context - непосредственно сам контекс, в который вы можете записать собственные поля
- logger - logger, используемый для вашего брокера (помечает сообщения с помощью message_id)
- message - необработанное сообщение (если вам нужен доступ к нему)
При этом, благодаря contextlib.ContextVar, message всегда соответствует контексту текущего процесса обработки.
Доступ к полям контекста¶
По умолчанию, как в примере выше, контекст ищет объект исходя из названия аргумента.
1 2 3 4 5 6 7 8 9 10 11 12 | |
Доступ по имени¶
Иногда у вас может возникнуть необходимость использовать другое название для аргумента (не то, под которым он хранится в контексте). Или даже получить доступ не ко всему объекту, а только к его полю или методу. Для этого просто укажите по имени, что вы хотите получить - и контекст предоставит вам нужный объект.
1 2 3 4 5 6 7 8 9 10 | |
Annotated¶
Способ по умолчанию не слишком удобен, если вам необходимо использовать одно и то же поле контекста по всему проекту. Также, оно требует явного указания аннотации типа входящего аргумента, если мы хотим пользоваться автодополнением нашей IDE. Для того, чтобы избежать длинных цепочек импортов и дублирования кода, Context полностью совместим с typing.Annotated.
1 2 3 4 5 6 7 8 9 10 11 | |
Для вашего удобства Propan уже содержит аннотации для существующих полей контекста. Вы можете просто импортировать их и использовать в вашем коде.
1 2 3 4 5 6 7 8 9 10 11 12 | |
Значения по умолчанию¶
Если же вы попробуете получить доступ к полю, которого нет в глобальном контексте, вы получите ошибку pydantic.ValidationError.
Однако, вы можете установить значение по умолчанию, если испытываете в этом необходимость.
1 2 3 4 5 6 7 8 | |
Приведение типов контекста¶
По умолчанию, поля контекста НЕ ПРИВОДЯТСЯ к типу, указанному в их аннотации. Если вам необходим этот функционал, вы просто можете установить соотвествующий флаг.
1 2 3 4 5 6 7 8 | |
Объявление полей контекста¶
Глобально¶
Для объявления полей контекста необходимо просто вызвать метод context.set_global с указанием ключа, по которому объект будет помещен в контекст.
1 2 3 4 5 6 7 8 | |
При этом поле становится глобальным полем контекста: оно не зависит от текущего обработчика сообщения (в отличие от message)
Для удаления поля из контекста просто используйте reset_global
context.reset_global("my_key")
Локально¶
Для установки локального контекста (он будет действовать во всех функциях, вызванных внутри него) используйте контекстный менеджер scope
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Также, контекст можно установить самостоятельно: тогда он будет действовать в рамках текущего стека вызовов до тех пор, пока вы его не очистите.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Использование в других функциях¶
По умолчанию контекст доступен там же, где и Depends:
- в хуках жизненного цикла
- обработчиках сообщений
- зависимостях
Depends¶
При использовании Context в Depends нет необходимости писать дополнительный код: как и вложенные Depends, Context также доступен по умолчанию.
1 2 3 4 5 6 7 8 9 10 11 12 | |
Обычные функции¶
Если же вы хотите использовать контекст и в других функциях, просто используйте декоратор @apply_types. При этом
контекст вызванной функции будет соответсвовать контексту обработчика события, из которого она вызвана.
1 2 3 4 5 6 7 8 9 10 11 12 | |
В примере выше мы не передавали при вызове функции logger, он был помещен из контекста.