Skip to content

More intuitive channel layer hook #284

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 5 additions & 22 deletions .github/workflows/test-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ on:

jobs:
python-source:
runs-on: ubuntu-latest
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
settings-module: ["single_db", "multi_db"]
operating-system: ["ubuntu-latest", "windows-latest"]
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
Expand All @@ -28,26 +30,7 @@ jobs:
- name: Install Python Dependencies
run: pip install --upgrade pip hatch uv
- name: Run Single DB Tests
run: hatch test --python ${{ matrix.python-version }} --ds=test_app.settings_single_db -v

python-source-multi-db:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Use Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Python Dependencies
run: pip install --upgrade pip hatch uv
- name: Run Multi-DB Tests
run: hatch test --python ${{ matrix.python-version }} --ds=test_app.settings_multi_db -v
run: hatch test --python ${{ matrix.python-version }} --ds=test_app.settings_${{matrix.settings-module}} -v

python-formatting:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -76,5 +59,5 @@ jobs:
python-version: 3.x
- name: Install Python Dependencies
run: pip install --upgrade pip hatch uv
- name: Check Python formatting
- name: Run Python type checker
run: hatch run python:type_check
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# ReactPy-Django Build Artifacts
src/reactpy_django/static/reactpy_django/client.js
src/reactpy_django/static/reactpy_django/index.js
src/reactpy_django/static/reactpy_django/index.js.map
src/reactpy_django/static/reactpy_django/pyscript
src/reactpy_django/static/reactpy_django/morphdom

Expand Down
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ Don't forget to remove deprecated code on each major release!

## [Unreleased]

- Nothing (yet)!
### Changed

- Updated the interface for `reactpy.hooks.use_channel_layer` to be more intuitive.
- Arguments now must be provided as keyworded arguments.
- The `name` argument has been renamed to `channel`.
- The `group_name` argument has been renamed to `group`.
- The `group_add` and `group_discard` arguments have been removed for simplicity.

### [5.2.1] - 2025-01-10

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# <img src="https://raw.githubusercontent.com/reactive-python/reactpy/main/branding/svg/reactpy-logo-square.svg" align="left" height="45"/> ReactPy-Django

<p>
<a href="https://github.com/reactive-python/reactpy-django/actions?query=workflow%3ATest">
<img src="https://github.com/reactive-python/reactpy-django/workflows/Test/badge.svg?event=push">
<a href="https://github.com/reactive-python/reactpy-django/actions/workflows/test-python.yml">
<img src="https://github.com/reactive-python/reactpy-django/actions/workflows/test-python.yml/badge.svg">
</a>
<a href="https://pypi.python.org/pypi/reactpy-django">
<img src="https://img.shields.io/pypi/v/reactpy-django.svg?label=PyPI">
Expand Down
8 changes: 4 additions & 4 deletions docs/examples/python/use_channel_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
@component
def my_component():
async def receive_message(message):
set_message(message["text"])
set_message_data(message["text"])

async def send_message(event):
if event["key"] == "Enter":
await sender({"text": event["target"]["value"]})

message, set_message = hooks.use_state("")
sender = use_channel_layer("my-channel-name", receiver=receive_message)
message_data, set_message_data = hooks.use_state("")
sender = use_channel_layer(group="my-group-name", receiver=receive_message)

return html.div(
f"Received: {message}",
f"Received: {message_data}",
html.br(),
"Send: ",
html.input({"type": "text", "onKeyDown": send_message}),
Expand Down
10 changes: 5 additions & 5 deletions docs/examples/python/use_channel_layer_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

@component
def my_sender_component():
sender = use_channel_layer(group_name="my-group-name")
sender = use_channel_layer(group="my-group-name")

async def submit_event(event):
if event["key"] == "Enter":
Expand All @@ -21,10 +21,10 @@ async def submit_event(event):
def my_receiver_component_1():
message, set_message = hooks.use_state("")

async def receive_event(message):
async def receive_message(message):
set_message(message["text"])

use_channel_layer(group_name="my-group-name", receiver=receive_event)
use_channel_layer(group="my-group-name", receiver=receive_message)

return html.div(f"Message Receiver 1: {message}")

Expand All @@ -33,9 +33,9 @@ async def receive_event(message):
def my_receiver_component_2():
message, set_message = hooks.use_state("")

async def receive_event(message):
async def receive_message(message):
set_message(message["text"])

use_channel_layer(group_name="my-group-name", receiver=receive_event)
use_channel_layer(group="my-group-name", receiver=receive_message)

return html.div(f"Message Receiver 2: {message}")
5 changes: 3 additions & 2 deletions docs/examples/python/use_channel_layer_signal_receiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
def my_receiver_component():
message, set_message = hooks.use_state("")

async def receive_event(message):
async def receive_message(message):
set_message(message["text"])

use_channel_layer("my-channel-name", receiver=receive_event)
# This is defined to receive any messages from both "my-channel-name" and "my-group-name".
use_channel_layer(channel="my-channel-name", group="my-group-name", receiver=receive_message)

return html.div(f"Message Receiver: {message}")
10 changes: 6 additions & 4 deletions docs/examples/python/use_channel_layer_signal_sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ class ExampleModel(Model): ...
def my_sender_signal(sender, instance, **kwargs):
layer = get_channel_layer()

# Example of sending a message to a channel
async_to_sync(layer.send)("my-channel-name", {"text": "Hello World!"})

# Example of sending a message to a group channel
# EXAMPLE 1: Sending a message to a group.
# Note that `group_send` requires using the `group` argument in `use_channel_layer`.
async_to_sync(layer.group_send)("my-group-name", {"text": "Hello World!"})

# EXAMPLE 2: Sending a message to a single channel.
# Note that this is typically only used for channels that use point-to-point communication
async_to_sync(layer.send)("my-channel-name", {"text": "Hello World!"})
29 changes: 29 additions & 0 deletions docs/examples/python/use_channel_layer_single.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from reactpy import component, hooks, html

from reactpy_django.hooks import use_channel_layer


@component
def my_sender_component():
sender = use_channel_layer(channel="my-channel-name")

async def submit_event(event):
if event["key"] == "Enter":
await sender({"text": event["target"]["value"]})

return html.div(
"Message Sender: ",
html.input({"type": "text", "onKeyDown": submit_event}),
)


@component
def my_receiver_component():
message, set_message = hooks.use_state("")

async def receive_message(message):
set_message(message["text"])

use_channel_layer(channel="my-channel-name", receiver=receive_message)

return html.div(f"Message Receiver 1: {message}")
2 changes: 1 addition & 1 deletion docs/src/about/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ By utilizing `hatch`, the following commands are available to manage the develop

The `hatch test` command is a wrapper for `pytest`. Hatch "intercepts" a handful of arguments, which can be previewed by typing `hatch test --help`.

Any additional arguments in the `test` command are directly passed on to pytest. See the [pytest documentation](https://docs.pytest.org/en/stable/reference/reference.html#command-line-flags) for what additional arguments are available.
Any additional arguments in the `test` command are provided directly to pytest. See the [pytest documentation](https://docs.pytest.org/en/stable/reference/reference.html#command-line-flags) for what additional arguments are available.

### Linting and Formatting

Expand Down
2 changes: 1 addition & 1 deletion docs/src/learn/your-first-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Additionally, you can pass in `#!python args` and `#!python kwargs` into your co

???+ tip "Components are automatically registered!"

ReactPy-Django will automatically register any component that is referenced in a Django HTML template. This means you [typically](../reference/utils.md#register-component) do not need to manually register components in your **Django app**.
ReactPy-Django will automatically register any component that is referenced in a Django HTML template. This means you typically do not need to [manually register](../reference/utils.md#register-component) components in your **Django app**.

Please note that this HTML template must be properly stored within a registered Django app. ReactPy-Django will output a console log message containing all detected components when the server starts up.

Expand Down
2 changes: 2 additions & 0 deletions docs/src/reference/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ This allows you to embedded any number of client-side PyScript components within

<!--pyscript-setup-required-end-->

{% include-markdown "./template-tag.md" start="<!--pyscript-webtypy-start-->" end="<!--pyscript-webtypy-end-->" %}

{% include-markdown "./template-tag.md" start="<!--pyscript-js-exec-start-->" end="<!--pyscript-js-exec-end-->" %}

{% include-markdown "./template-tag.md" start="<!--pyscript-multifile-start-->" end="<!--pyscript-multifile-end-->" trailing-newlines=false preserve-includer-indent=false %}
Expand Down
Loading
Loading