Skip to content

2.0.2

Compare
Choose a tag to compare
@david-lev david-lev released this 30 Oct 15:13
· 100 commits to master since this release

What's Changed

Update with pip: pip3 install -U pywa

Important

Breaking Changes! Please see the Migration Guide for instructions on updating from earlier versions.

  • [listeners]: Listeners are a new way to handle incoming user updates (messages, callbacks, etc.). They are more flexible, faster, and easier to use than handlers.
  • [sent_message]: The SentMessage object returned by send_message, send_image, etc., contains the message ID and allows to act on the sent message with methods like reply_x, wait_for_x etc.
  • [filters]: Filters are now objects that can be combined using logical operators. They are more powerful and flexible than the previous filter system.
  • [handlers] allow to register callbacks without WhatsApp instance
  • [flows] allow pythonic conditionals in If component
  • [flows]: A new method FlowCompletion.get_media(types.Image, key="img") allows you to construct a media object and perform actions like .download() on it.
  • [flows]: Decrypt media directly from FlowRequest using .decrypt_media(key, index).
  • [flows] rename .data_key and .from_ref to .ref
  • [client]: The client can run without a token but won’t allow API operations (only webhook listening).
  • [server] rely on update hash instead of update id to avid duplicate updates
  • [callback] allow to override callback data id
  • [utils] bump graph-api version to 21.0
# my_handlers.py

from pywa import WhatsApp, filters, types, listeners

# You can register callback without th instance!
@WhatsApp.on_message(filters.text & filters.matches("store")) # combine filters with & operator
def store(_: WhatsApp, m: types.Message):
    try:
        age = m.reply("How old are you?", buttons=[types.Button("Cancel", "cancel")]).wait_for_reply( # wait for a reply
            filters=filters.text & filters.new(lambda _, m: m.text.isdigit()), # create a new filter
            cancelers=filters.callback_button & filters.matches("cancel"), # cancel the listener if the user clicks the cancel button
            timeout=10, # set a timeout
        )
        m.reply(f"Your age is {age.text}")
    except listeners.ListenerCanceled:
        m.reply("You cancelled the store")
    except listeners.ListenerTimeout:
        m.reply("You took too long to reply")

# main.py

from pywa import WhatsApp
from . import my_handlers

wa = WhatsApp(..., handlers_modules=[my_handlers])

# run the server
from pywa.types.flows import *

FlowJSON(
    version=pywa.Version.FLOW_JSON,
    screens=[
        Screen(
            id="WELCOME",
            title="Welcome",
            data=[is_admin := ScreenData(key="is_admin", example=True)],
            layout=Layout(
                children=[
                    animal := TextInput(
                        name="animal",
                        label="Animal",
                        helper_text="Type: cat",
                    ),
                    If(
                        condition=is_admin.ref & (animal.ref == "cat"), # we can use python operators
                        then=[TextHeading(text="It is a cat")],
                        else_=[TextHeading(text="It is not a cat")],
                    ),
                ]
            ),
        )
    ],
)

Full Changelog: 1.26.0...2.0.2