Releases: david-lev/pywa
1.26.0
What's Changed
Update with pip:
pip3 install -U pywa
- [flows] adding support of
RichText
- [flows] adding support of
markdown
inTextBody
andTextCaption
- [flows] adding
sensitive
attr to Screen, allowing to hide specific fields from the response summary - [client] adding
reply_to_message
arg tosend_location
,request_location
,send_sticker
, andsend_audio
- [message] adding
reply_location_request
flow = FlowJSON(
screens=[
screen_1 := Screen(
layout=Layout(
children=[
RichText(
text=[
"# Heading 1",
"## Heading 2",
"Let’s make a **bold** statement",
"Let's make this text *italic*",
"Let's make this text ~~Strikethrough~~",
"This text is ~~***really important***~~",
"This is a [pywa docs](https://pywa.readthedocs.io/)",
"This is a ordered list:",
"1. Item 1",
"2. Item 2",
"This is a unordered list:",
"- Item 1",
"- Item 2",
"![image](data:image/png;base64,<base64 content>)",
"| Tables | Are | Cool |",
"| ------------- | ------------- | ----- |",
"| col 3 is | right-aligned | $1600 |",
"| col 2 is | centered | $12 |",
],
),
]
),
)
]
Full Changelog: 1.25.0...1.26.0
1.25.0
What's Changed
Update with pip:
pip3 install -U pywa
- [handlers] adding priority
- [client] adding QR methods (create update get and delete)
- [client] adding
get_flow_metrics
method - [flows] adding to
DataSource
support for images/colors - [flows] support
datetime
objs inDatePicker
- [flows] support
Screen
when using.data_key_of(...)
and.form_ref_of(...)
- [flows] update flow json with indent and without ensuring ascii
- [flows] adding
health_status
toFlowDetails
from pywa import WhatsApp, types
wa = WhatsApp(...)
@wa.on_message(filters.text, priority=2)
def one(_: WhatsApp, m: types.Message):
...
@wa.on_message(filters.text, priority=3) # will be called before `one`
def two(_: WhatsApp, m: types.Message):
...
wa.create_qr_code(prefilled_message="Hi, I am interested in your product", image_type="SVG")
wa.get_flow_metrics(
flow_id=...,
metric_name=types.FlowMetricName.ENDPOINT_REQUEST_COUNT,
granularity=types.FlowMetricGranularity.DAY,
since=datetime.date(2024, 8, 1),
)
flow = FlowJSON(
screens=[
screen_1 := Screen(
data=[name := ScreenData(key="name", example="David")], # data key in screen_1
layout=...
),
screen_2 := Screen(
layout=Layout(
children=[
TextHeading(text=name.data_key_of(screen_1)), # reference to data key in screen_1
date := DatePicker(
name="date",
label="When?",
min_date=datetime.date(2024, 8, 1), # date obj in DatePicker
max_date=datetime.date(2024, 8, 30),
)
]
),
)
]
)
Full Changelog: 1.24.0...1.25.0
1.24.0
What's Changed
Update with pip:
pip3 install -U pywa
- [server] validating
X-Hub-Signature-256
header - [requirements] removing
requests
- [server] default callback url registration delay to 3 sec
wa = WhatsApp(
validate_updates=True, # Default: True
app_secret="122hifewyhf9we372d93676",
...
)
Full Changelog: 1.23.0...1.24.0
1.23.0
What's Changed
Update with pip:
pip3 install -U pywa
- [client] allowing to manage multiple numbers from the same client (Partner solutions)
- [flows] adding
.respond()
shortcut forFlowRequest
- [flows] allowing body in
FlowResponseError
subclasses
from pywa import WhatsApp, types, filters
wa = WhatsApp(token="xyzxyz", ...) # `phone_id` is now optional
wa.send_message(
sender=..., # now you can specify sender
to=...,
text="Hello from PyWa!"
)
@wa.on_message(filters.text.command("start"))
def on_start(_: WhatsApp, msg: types.Message):
if msg.recipient == ...: # or check the recipient
...
elif msg.recipient == ...:
...
msg.reply(...) # .reply() is automatically replaying to the sender
from pywa import WhatsApp, types
wa = WhatsApp(...)
@wa.on_flow_request("/my-flow")
def my_flow_handler(_: WhatsApp, req: types.FlowRequest) -> types.FlowResponse:
return req.respond( # instead of instantiating FlowResponse with req.version
screen="SIGN_UP",
data={}
)
Full Changelog: 1.22.0...1.23.0
1.22.0
What's Changed
Update with pip:
pip3 install -U pywa
- [handlers] introducing new way to help split flow endpoint logic to multiple handlers (see example)
- [client] adding
add_flow_request_handler
method to registerFlowRequestHandler
s - [flows] pop
flow_token
fromFlowCompletion
.response - [docs] update examples
from pywa import WhatsApp, types
wa = WhatsApp(...)
@wa.on_flow_request("/my-flow")
def my_flow_handler(_: WhatsApp, flow: types.FlowRequest) -> types.FlowResponse | None:
...
@my_flow_handler.on(action=types.FlowRequestActionType.INIT)
def on_init(_: WhatsApp, request: types.FlowRequest) -> types.FlowResponse:
...
@my_flow_handler.on(action=types.FlowRequestActionType.DATA_EXCHANGE, screen="SIGN_UP")
def on_signup(_: WhatsApp, request: types.FlowRequest) -> types.FlowResponse:
...
@my_flow_handler.on(
action=types.FlowRequestActionType.DATA_EXCHANGE,
screen="LOGIN",
data_filter=lambda _, data: not user_repository.exists(data["email"]),
)
def if_not_registered(_: WhatsApp, request: types.FlowRequest) -> types.FlowResponse | None:
...
Full Changelog: 1.21.0...1.22.0
1.21.0
What's Changed
Update with pip:
pip3 install -U pywa
Caution
- [server] This version drops support for non-asynchronous WSGI applications (Flask without
asgiref
) - [flows]
version
is now required inFlowJSON
- [flows] added new components
PhotoPicker
,DocumentPicker
,If
andSwitch
- [flows] added
.data_key_of
and.form_ref_of
to refer from other screens - [flows] added
description
toCheckboxGroup
and toRadioButtonsGroup
- [utils] adding
flow_request_media_decryptor
function to decrypt medias from flow requests - [client] allow updating flow application id with
update_flow_metadata
- [server] remove event loop
- [docs] update examples
- [version] bump
FLOW_JSON
version to4.0
from pywa import WhatsApp, utils, types
from pywa.types.flows import *
wa = WhatsApp(...)
my_flow = FlowJSON(
version="4.0",
screens=[
Screen(
id="UPLOAD_DRIVER_LICENSE",
title="Upload Driver License",
layout=Layout(
children=[
doc := DocumentPicker(
name="driver_license",
label="Driver License",
min_uploaded_documents=1,
max_uploaded_documents=1,
allowed_mime_types=["application/pdf", "image/jpeg"],
),
Footer(
label="Next",
enabled=True,
on_click_action=Action(
name=FlowActionType.DATA_EXCHANGE,
payload={"doc": doc.form_ref_of("UPLOAD_DRIVER_LICENSE")},
),
),
]
)
)
]
)
@wa.on_flow_request("/flow")
def on_flow_request(_, flow: types.FlowRequest):
media_id, filename, media_bytes = utils.flow_request_media_decryptor_sync(flow.data["doc"])
with open(filename, "wb") as f:
f.write(media_bytes)
...
Full Changelog: 1.20.2...1.21.0
1.20.2
What's Changed
Update with pip:
pip3 install -U pywa
- [pywa] adding official support for async (limited support for now)
- [server] expose
webhook_challenge_handler
,webhook_update_handler
andget_flow_request_handler
for custom server implementations - [server] improve continue/stop handling
- [client] adding
skip_duplicate_updates
when callbacks take too long to return (~25s), defaults to True - [client,handlers] allow to override
continue_handling
# wa.py
from pywa_async import WhatsApp, types # Import from `pywa_async` instead of `pywa`
import fastapi
fastapi_app = FastAPI()
wa = WhatsApp(..., server=fastapi_app)
@wa.on_message()
async def echo_media(_: WhatsApp, msg: types.Message):
await msg.reply("I'm using PyWa async!")
Run with uvicorn:
uvicorn wa:fastapi_app
Full Changelog: 1.18.1...1.20.2
1.19.0-rc.3
What's Changed
Update with pip:
pip3 install -U pywa==1.19.0-rc.3
- [api] fix uploads
- [server] expose
webhook_challenge_handler
,webhook_update_handler
andflow_request_handler
Full Changelog: 1.19.0-rc.2...1.19.0-rc.3
1.19.0-rc.2
What's Changed
Update with pip:
pip3 install -U pywa==1.19.0-rc.2
- [client] adding
skip_duplicate_updates
when callbacks take too long to return (~25s), defaults to True - [client,handlers] allow to override
continue_handling
- [message] fix async constructors
- [api] remove
requests_toolbelt
from deps - [handlers] fix dynamic field name when
factory_before_filters
Full Changelog: 1.19.0-rc.1...1.19.0-rc.2
1.19.0-rc.1
What's Changed
Update with pip:
pip3 install -U pywa==1.19.0-rc.1
- [async] adding beta support for async!
from pywa_async import WhatsApp, types # Import from `pywa_async` instead of `pywa`
wa = WhatsApp(...)
@wa.on_message(filters.media)
async def echo_media(_: WhatsApp, message: types.Message):
await message.copy(to=message.sender)
Full Changelog: 1.18.1...1.19.0-rc.1