Skip to content
\n

I'd be surprised there isn't a recommended way to do this easily, or I didn't read the documentation well.

\n

I understand that we can write something like this:

\n
# in main\napp.service = service # just create attribute dynamically\n\n# in handler\nservice = typing.cast(MyService, context.application.service)
\n

or like this

\n
# in main\napp.bot_data[\"service\"] = service\n\n# in handler\nservice = typing.cast(MyService, context.bot_data[\"service\"])
\n

or even make a variable at the module level.

\n

But these solutions look dirty from the point of view of typing and testability.

\n

The closest result I was able to achieve was using custom Application and CallbackContext classes.

\n
Full code example\n
import typing as t\n\nfrom telegram import Update\nfrom telegram.ext import (\n    ApplicationBuilder,\n    Application,\n    CommandHandler,\n    ContextTypes,\n    CallbackContext,\n    ExtBot,\n)\n\n\nADict = dict[t.Any, t.Any]\n\n\nclass MyService: ...\n\n\nclass MyApplication(Application):\n    def __init__(self, service: MyService, **kwargs):\n        super().__init__(**kwargs)\n        self.service = service\n\n\nclass MyContext(CallbackContext[ExtBot[None], ADict, ADict, ADict]):\n    @property\n    def service(self):\n        return t.cast(MyApplication, self.application).service\n\n\nasync def hello(update: Update, context: MyContext) -> None:\n    print(context.service) # <__main__.MyService object at 0x7f174d334680>\n\n\ndef main():\n    service = MyService()\n\n    context_types = ContextTypes(context=MyContext)\n\n    app = (\n        ApplicationBuilder()\n        .application_class(MyApplication, {\"service\": service})\n        .context_types(context_types)\n        .token(\"...\")\n        .build()\n    )\n    app.add_handler(CommandHandler(\"hello\", hello))\n    app.run_polling()
\n
\n

But even here we need to use type cast because in the context the application property is annotated as Application[ExtBot[None], Any, ADict, ADict, ADict, Any], despite the fact that in ApplicationBuilder we specified our application class.

\n

In general, I would like to know if my last example can be made better, maybe there are other alternatives and I missed something?
\nIt is also strange that I did not find issues and discussions on a similar topic, although the topic, in my opinion, is important. It is very interesting how others played with such a problem.

","upvoteCount":1,"answerCount":2,"acceptedAnswer":{"@type":"Answer","text":"

I usually use a custom context, see e.g. https://github.com/python-telegram-bot/ptbcontrib/tree/main/ptbcontrib/username_to_chat_api or https://docs.python-telegram-bot.org/en/stable/examples.contexttypesbot.html

\n

Not sure that's fully accommodating of your fully type cast example here

","upvoteCount":2,"url":"https://github.com/python-telegram-bot/python-telegram-bot/discussions/4902#discussioncomment-14039742"}}}
Discussion options

You must be logged in to vote

Replies: 2 comments

Comment options

You must be logged in to vote
0 replies
Answer selected by nectarindev
Comment options

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet
3 participants