You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
pattern in `pywa_async/types/<file>.py`: star-import the sync module to re-export everything unchanged, import the
311
+
specific class under a private alias, then subclass it together with the async base to override only the methods
312
+
that need to become `async`:
313
+
314
+
```python
315
+
from pywa.types.message import*
316
+
from pywa.types.message import Message as _Message
317
+
318
+
classMessage(BaseUserUpdateAsync, _Message):
319
+
"""Async override: same fields as the sync `Message`; shortcut methods are async."""
320
+
321
+
asyncdefreply_text(self, ...): ...
322
+
```
323
+
324
+
So when adding a new field to a type, edit the `pywa/types/<file>.py` dataclass only (it's shared); when adding a
325
+
new *client-shortcut method*, add the sync version to the sync class and the async version to the
326
+
`pywa_async/types/<file>.py` override class.
327
+
328
+
#### Listeners
329
+
330
+
`listeners.py` implements inline "wait for the next matching update" mechanics (`msg.wait_for_reply(...)`,
331
+
`msg.wait_for_click(...)`). Unlike `api.py`/`client.py`, the async version (`pywa_async/listeners.py`) is **not** a thin override —
332
+
asyncio-based waiting requires different control flow, so it's independently implemented rather than subclassed.
333
+
Keep both in sync by behavior, not by inheritance.
222
334
223
335
#### Utils
224
336
@@ -233,26 +345,35 @@ Contains the custom exceptions used in the library.
233
345
The `cli.py` and `__main__.py` files implement the command line interface (run using the `pywa` command) to run the dev
234
346
server, send messages etc.
235
347
236
-
#### Async
237
-
238
-
The async version of pywa (`pywa_async`) preserves the same structure as the sync version (`pywa`). Most of the code in
239
-
the async version is inherited from the sync version, while overriding every api-related method to be async. So when you
240
-
make changes to the sync version, make sure to apply the same changes to the async version.
241
-
242
348
#### Docs
243
349
244
-
The documentation is written in reStructuredText and is located in the `docs/source/content` directory. The
245
-
documentation is built using Sphinx and hosted on ReadTheDocs.
350
+
The documentation is written in [reStructuredText](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html) and is located in the `docs/source/content` directory. The
351
+
documentation is built using [Sphinx](https://www.sphinx-doc.org/en/master/index.html) and hosted on [ReadTheDocs](https://app.readthedocs.org/projects/pywa/).
246
352
247
353
#### Tests
248
354
249
-
The tests are located in the `tests` directory and are written using `pytest`.
355
+
The tests live in `tests/` and are written using [pytest](https://docs.pytest.org/en/stable/). The split mirrors
356
+
the modules above — put new tests next to the existing ones for the module you touched, not in a new file:
250
357
251
-
- Run all tests:
252
-
```bash
253
-
pytest
254
-
```
255
-
- When adding new features or fixing bugs, please write corresponding tests:
256
-
- Add tests for client methods/options in `test_client.py` and `test_async.py`.
257
-
- Add tests for new filters in `test_filters.py`.
258
-
- Add tests for new types/updates in `test_types.py` or `test_updates.py`.
358
+
```bash
359
+
uv run pytest # full suite
360
+
uv run pytest tests/test_client.py # one file
361
+
uv run pytest tests/test_client.py -k test_name # one test
362
+
```
363
+
364
+
-`test_api.py` / `test_api_async.py` — `api.py` request-building/params (sync and async are separate files here,
365
+
since `GraphAPIAsync` methods must each be awaited).
366
+
-`test_client.py` / `test_async.py` — `client.py`; add tests for every new/changed client method or option to
367
+
**both** files (`test_async.py` covers `pywa_async`-specific and async-only behavior).
368
+
-`test_server.py` — webhook verification, parsing, and handler-routing decisions in `server.py`.
369
+
-`test_handlers.py` — handler classes and the `@wa.on_*` decorator machinery.
370
+
-`test_listeners.py` — `.wait_for_reply(...)` / `.ask(...)` mechanics (sync and async).
371
+
-`test_filters.py` — add a case here for every new filter in `filters.py`.
372
+
-`test_types.py` / `test_updates.py` — new/changed dataclasses go in `test_types.py`; parsing of new update shapes
373
+
(raw JSON → typed object) goes in `test_updates.py`.
Copy file name to clipboardExpand all lines: docs/source/content/cli.rst
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -78,7 +78,7 @@ Both ``pywa dev`` and ``pywa run`` share the following options:
78
78
* ``path``: Optional positional argument pointing to the Python file containing the ``WhatsApp`` instance.
79
79
* ``--host <str>``: The host to bind the socket to. Default: ``127.0.0.1``.
80
80
* ``--port <int>``: The port to bind the socket to. Default: ``8000``.
81
-
* ``--app <str>``: Specify the variable name of the ``WhatsApp`` client instance within the script (e.g., if you set ``my_wa_client = WhatsApp(...)``, pass ``--app my_wa_client``). By default, Pywa auto-detects instances named ``wa``, ``bot``, ``client``, ``app``, or ``main``.
81
+
* ``--app <str>``: Specify the variable name of the ``WhatsApp`` client instance within the script (e.g., if you set ``my_wa_client = WhatsApp(...)``, pass ``--app my_wa_client``). By default, Pywa auto-detects ``WhatsApp`` instances in the script. If multiple instances exist, you must specify which one to use with this option - otherwise, the first instance found will be used.
82
82
* ``--entrypoint <str>``: Explicit entrypoint string (e.g., ``main:wa``). This overrides ``path`` and ``--app``.
83
83
* ``--log-level <level>``: Set the logging level (choices: ``critical``, ``error``, ``warning``, ``info``, ``debug``, ``trace``).
84
84
* ``--ssl-keyfile <path>``: Path to an SSL key file.
@@ -87,7 +87,7 @@ Both ``pywa dev`` and ``pywa run`` share the following options:
87
87
Production-only Options (``pywa run``)
88
88
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
89
89
90
-
* ``--workers <int>``: Number of worker processes to run.
90
+
* ``--workers <int>``: Number of worker processes to run (this will disable the listeners feature! e.g. ``msg.wait_for_reply(...)``). Default: ``1``.
91
91
* ``--proxy-headers`` / ``--no-proxy-headers``: Enable/Disable proxy headers (``X-Forwarded-Proto``, ``X-Forwarded-For``) to populate the request's URL scheme and client IP address.
92
92
* ``--forwarded-allow-ips <str>``: Comma-separated list of IPs to trust with proxy headers. Use ``*`` to trust all IPs.
93
93
* ``--timeout-keep-alive <int>``: Close keep-alive connections if no new data is received within this timeout (in seconds).
"E711", # forbid `== None` / `!= None`; use `is None` / `is not None` instead
125
+
"E712", # forbid `== True` / `== False`; use `is`/`is not` or plain truthiness instead; exempted below for `tests/test_flows.py`, which asserts against literal booleans in Flow JSON conditions
f"❌ Error: File '{out_file}' already exists. Aborting to prevent overwrite. Use --out to specify a different output directory or remove the existing file."
338
338
)
339
339
return
340
-
out_file.write_text(code)
340
+
out_file.write_text(code, encoding="utf-8")
341
341
print(f"✅ Created new Pywa project at {out_file.resolve()}")
0 commit comments