Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

ConversationHandler#2802

Bibo-Joshi started this conversation inFeature Suggestions
Dec 1, 2021· 3 comments· 8 replies
Discussion options

There has been some discussion onConversationHandler in the user group starting athttps://t.me/pythontelegrambotgroup/544706, which got a bit too lengthy for the user group. I'll try to copy the relevant parts to here in a thread-like style

related code snippet:https://pastebin.com/RxZDLyNW (see also#2802 (comment))

David Shiko

Hello guys!
I thought about CH (the hearth of any bot, because command handler is over simple to speak about it)
So I noticed some difficulties that come across at the start and want to announce them.
Logic and requirements which I will be guided:

  1. Most of bots developers are not so experienced so PTB should to avoid an advanced python features.
  2. Bots are often an mediate stage between Hello word and really backend dev with flask, django, etc.
  3. Inherently PTB logic and archeticture is the same as flask and django.
  4. Despite a simplicity which we want with PTB, the last one should avoid wrong architecture and approaches for no learning users bad ways.
    I will split my announce in a few messages because it may be long.
You must be logged in to vote

Replies: 3 comments 8 replies

Comment options

Bibo-Joshi
Dec 1, 2021
Maintainer Author

David Shiko

Message 1.
Functions vs classes (no related to PTB directly):
I met many questions about "How to pass data from handler to handler". This is specific CH question.
In regular script we used to do the next:

def get_name():    name = input('What is your name')    ... # Some checks    return namedef get_user():    name = get_name()    age = get_age()    save_data()    ...  # other things

But with using are classes we are avoiding this question because saving all data are inside an instance
user.get_name() # self.name = input inside

So maybe we want to use a classes instead ofcontext.*_data ?
A more global question is "is se need a context at all in our handlers?".
Because I personally only usingcontext.*_data and maybecontext.bot.

You must be logged in to vote
5 replies
@Bibo-Joshi
Comment options

Bibo-JoshiDec 1, 2021
Maintainer Author

Arun Mani J

  1. Context can be taken as a channel for intraprocess communication.
  2. Classes are quite rigid in structure and by the definition, they must have same layout throughout the program.
    That is, dynamically adding and removing attributes is a very bad design.
  3. Dictionary, it is. They are designed to dynamically updated and so context uses dict.
  4. But as it is, context is very flexible in mapping any immutable object to any.
  5. I don't understand how context can be replaced by classes without polluting pureness of Telegram objects. That is, there is context.args to get args of a command, if we move this to Message.args, then there will be a very big conflict between Telegram bot spec and ours.

This confuses users more. Context style message passing is also available in Flask. We are providing a built in solution to avoid boilerplate messy code on users side

@Bibo-Joshi
Comment options

Bibo-JoshiDec 1, 2021
Maintainer Author

David Shiko

Context is a great feature, but overkill in most cases.

  1. In my code, I always declare all the attributes in the initialization method, in most cases it isNone
  2. In my opinion, usingself.user.name instead ofcontext.user_data ['user']. Name is much more readable (assigninguser = context.user_data ['user'] looks funny.
  3. I do not mean replacing the context, but the optional use of a class instead of a context.
@Bibo-Joshi
Comment options

Bibo-JoshiDec 1, 2021
Maintainer Author

Me

Context is a great feature, but overkill in most cases.

sure, you'll probably not need many of the attributes for many callbacks. but it comes at almost zero cost to have them. The alternative would be to go back to v11 stylecallbacks def callback(bot, update, user_data, bot_data, …) and all the pass_* arguments for the Handlers.
always passing asingle context argument from which you can choose to use or not to use something just makes the interface more consistent and less bloated.

user = context.user_data ['user'] looks funny.

Via ext.ContextTypes you can make user_data a custom class such that you can writecontext.user_data.data if that's more to your liking.

I do not mean replacing the context, but the optional use of a class instead of acontext.

I don't really understand this point.contextis an instance of a class. implementing all your callbacks as methods of a custom class is ofc fine, but that has little to do with whether or notcontext should be passed to those methods

@Bibo-Joshi
Comment options

Bibo-JoshiDec 1, 2021
Maintainer Author

David Shiko

The additional advantage of classes before function is structuring.
By classes you can bind multiple CH handlers into one logic structure.
So that's good way to distinguish between command (and other) handlers and CH handlers.


I mean 2 things:

  1. Putting handlers directly in states dict it's a messing between logic and implementation. So between menu and user defined handlers of states should be some interface.
  2. List of handlers for state instead of single handler is making a messy. Every state should have only one entry point.
@Bibo-Joshi
Comment options

Bibo-JoshiDec 1, 2021
Maintainer Author

Me

  1. Putting handlers directly in states dict it's a messing between logic and implementation. So between menu and user defined handlers of states should be some interface.

I can't follow you here. what exactly do you mean by "logic", "implementation" and "menu"?

  1. List of handlers for state instead of single handler is making a messy. Every state should have only one entry point.

I'd argue that having multiple handlers for a state can be useful, e.g. if in a state you want to be able to handle both messages and callback queries. But you don'thave to pass mutliple states. Ofc chaning CH such that it can accept a single handlers instead of[handler] is something that we can discuss :)

The additional advantage of classes before function is structuring.

Then I'd go back to my argument from#2802 (reply in thread) :)

Comment options

Bibo-Joshi
Dec 1, 2021
Maintainer Author

David Shiko

Message 2.
CH is just a menu in fact.

  1. As any other menu (and definition) it should be clear and verbose.
    We may consider it like a DTO (dataclass, pydantic schema, etc (when the purpose is definition rather than execution)).
  2. Menu should be separated from either internal logic and calls of bot methods.
  3. Regular menu always has a question-answer structure.
  4. To make things easier every menu should have only one "last and next step" and avoid multiple handlers for one state (as it's now).
  5. Filters for states (handlers) - A long theme, because it's creating additional questions as "Is I should handle incorrect data in my function or just ignore through filters" (It's also implicit).
  6. CH remind a django approach (rather than flask or fastapi) because it has no decorators like
@CH_state(filter-..., handler=MessageHandler, ...)    def some_handler(update, context):
You must be logged in to vote
1 reply
@Bibo-Joshi
Comment options

Bibo-JoshiDec 1, 2021
Maintainer Author

Me

I don't understand what point you're trying to make here. What's the punshline of this message?

what do you mean when you say "menu"? CH can do much more than just offer options to choose from in each step. At the very core, CH is a finite state machine

(https://en.wikipedia.org/wiki/Finite-state_machine)> when the purpose is definition rather than execution
I disagree. CH is a handler and it's purpose it to execute stuff.

Menu should be separated from either internal logic and calls of bot methods.

what do you mean by "internal logic"? internals of PTB? internals of CH? internals of your code?

Comment options

Bibo-Joshi
Dec 1, 2021
Maintainer Author

David Shiko

Message 3
So I did some example how CH may looks like. It's rather a pseudocode than a concrete implementation.
Pay attention how it easy (or not) to read comparing with standard CH.
I also mixed up an internal logic and definition logic (User and menu/states) - it's not my intention, I just don't have enough experience to decide is internal logic should inherit from definition or vice versa.
The reason of inheritance here - is to provide access tocurrent_state and other definition specific parameters.
Menu values are lists ("List style" ) -Is just to make similarity with 8-bit menu
https://www.shutterstock.com/image-vector/8bit-menu-screen-mobile-game-asset-459985495
(I also have another variants)


Message 4 (https://pastebin.com/RxZDLyNW)

You must be logged in to vote
2 replies
@Bibo-Joshi
Comment options

Bibo-JoshiDec 1, 2021
Maintainer Author

Me

what I see here is mostly "abstracting your callbacks into a custom class". THat's ofc fine if it helps you keeping your code structured, but I don't see a necessity to enforce this pattern.

From what I understand bound_class=User2 is supposed to mean that for each conversation, an instance of this class is created? You can achieve the same effect by doing something like

def callback(update, context):    # using a custom `CallbackContext` class    obj = context.conversation_objects(update)    obj.callback(update(, context))

I don't fully understand what thedefaults, menu and failed kwargs are supposed to be there for … could you elaborate?

@Bibo-Joshi
Comment options

Bibo-JoshiDec 1, 2021
Maintainer Author

David Shiko

Yes.
defaults, menu, failed it's are synonym for rpefallbacks, states, fallbacks, don't focus on it.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Labels
None yet
1 participant
@Bibo-Joshi

[8]ページ先頭

©2009-2025 Movatter.jp