Skip to content

Commit a61b5be

Browse files
committed
Merge remote-tracking branch 'origin/main' into backport-sourcing-consumer-config
# Conflicts: # nats/tests/test_js.py
2 parents 847e820 + c7896c1 commit a61b5be

131 files changed

Lines changed: 6905 additions & 621 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/check.yml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ jobs:
1919
- name: Set up Python
2020
uses: actions/setup-python@v6
2121
with:
22-
python-version: "3.8"
22+
python-version: "3.13"
2323

2424
- name: Install uv
2525
uses: astral-sh/setup-uv@v6
2626

2727
- name: Install the project
28-
run: uv sync --dev
28+
run: uv sync --only-group check
2929

3030
- name: Run format check
31-
run: uv run ruff format --check
31+
run: uv run --no-sync ruff format --check
3232

3333
lint:
3434
runs-on: ubuntu-latest
@@ -40,16 +40,16 @@ jobs:
4040
- name: Set up Python
4141
uses: actions/setup-python@v6
4242
with:
43-
python-version: "3.8"
43+
python-version: "3.13"
4444

4545
- name: Install uv
4646
uses: astral-sh/setup-uv@v6
4747

4848
- name: Install the project
49-
run: uv sync --dev
49+
run: uv sync --only-group check
5050

5151
- name: Run lint check
52-
run: uv run ruff check
52+
run: uv run --no-sync ruff check
5353

5454
spell:
5555
runs-on: ubuntu-latest
@@ -61,16 +61,16 @@ jobs:
6161
- name: Set up Python
6262
uses: actions/setup-python@v6
6363
with:
64-
python-version: "3.8"
64+
python-version: "3.13"
6565

6666
- name: Install uv
6767
uses: astral-sh/setup-uv@v6
6868

6969
- name: Install the project
70-
run: uv sync --dev
70+
run: uv sync --only-group check
7171

7272
- name: Run spell check
73-
run: uv run codespell
73+
run: uv run --no-sync codespell
7474

7575
type:
7676
runs-on: ubuntu-latest
@@ -82,7 +82,7 @@ jobs:
8282
- name: Set up Python
8383
uses: actions/setup-python@v6
8484
with:
85-
python-version: "3.8"
85+
python-version: "3.13"
8686

8787
- name: Install uv
8888
uses: astral-sh/setup-uv@v6
@@ -91,7 +91,7 @@ jobs:
9191
run: uv sync --dev
9292

9393
- name: Run type check
94-
run: uv run ty check nats-core nats-server
94+
run: uv run --no-sync ty check nats-core nats-server
9595

9696
build:
9797
runs-on: ubuntu-latest

.github/workflows/test.yml

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,26 @@ jobs:
1515
nats:
1616
runs-on: ubuntu-latest
1717
timeout-minutes: 20
18-
env:
19-
NATS_SERVER_VERSION: ${{ matrix.nats_version }}
2018
strategy:
2119
fail-fast: false
2220
matrix:
2321
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
24-
nats_version: ["latest"]
22+
nats-server-version: ["latest"]
2523

2624
steps:
2725
- name: Check out repository
2826
uses: actions/checkout@v5
2927

28+
- name: Set up Go
29+
uses: actions/setup-go@v6
30+
with:
31+
go-version: "stable"
32+
33+
- name: Install NATS Server
34+
run: |
35+
go install github.com/nats-io/nats-server/v2@${{ matrix.nats-server-version }}
36+
shell: bash
37+
3038
- name: Set up Python ${{ matrix.python-version }}
3139
uses: actions/setup-python@v6
3240
with:
@@ -36,15 +44,15 @@ jobs:
3644
uses: astral-sh/setup-uv@v6
3745

3846
- name: Install dependencies and project
47+
# Installed outside the workspace: uv.lock is pinned to >=3.13 for the
48+
# modern packages, so it cannot resolve the 3.8-3.12 legs of this matrix.
3949
run: |
40-
uv sync --dev
41-
./nats/scripts/install_nats.sh
50+
uv venv --no-project --python python
51+
uv pip install --python .venv/bin/python --editable ./nats --group ./nats/pyproject.toml:dev
4252
4353
- name: Run tests
4454
run: |
45-
uv run pytest -x -vv -s --continue-on-collection-errors ./nats/tests
46-
env:
47-
PATH: $HOME/nats-server:$PATH
55+
.venv/bin/python -m pytest -x -vv -s --continue-on-collection-errors ./nats/tests
4856
4957
project:
5058
name: ${{ matrix.project }} (python-${{ matrix.python-version }}, nats-server-${{ matrix.nats-server-version }}, ${{ matrix.os }})
@@ -54,7 +62,7 @@ jobs:
5462
python-version: ["3.13"]
5563
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
5664
nats-server-version: ["latest"]
57-
project: ["nats-server", "nats-core", "nats-key-value"]
65+
project: ["nats-server", "nats-core", "nats-jetstream", "nats-key-value"]
5866
steps:
5967
- name: Checkout repository
6068
uses: actions/checkout@v5
@@ -82,5 +90,5 @@ jobs:
8290
working-directory: ${{ matrix.project }}
8391

8492
- name: Run tests for ${{ matrix.project }}
85-
run: uv run pytest -v -n auto
93+
run: uv run --no-sync pytest -v -n auto
8694
working-directory: ${{ matrix.project }}

examples/docs/README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# NATS Documentation Examples
2+
3+
These are the Python equivalents of the docs examples published in the NATS
4+
documentation. They mirror the
5+
[Rust](https://github.com/nats-io/nats.rs/tree/main/async-nats/examples)
6+
and [Java](https://github.com/nats-io/nats.java/tree/main/examples/src/main/java/io/nats/examples/natsIoDoc)
7+
versions of the same examples.
8+
9+
The examples use the modern [`nats-core`](../../nats-core) client (and
10+
[`nats-jetstream`](../../nats-jetstream) for the JetStream example).
11+
They require **Python 3.13+**.
12+
13+
## Running
14+
15+
From the workspace root:
16+
17+
```bash
18+
uv sync
19+
uv run python examples/docs/basics_publish.py
20+
```
21+
22+
Most examples connect to the public `demo.nats.io` server. The JetStream
23+
example (`jetstream_basic.py`) needs a local server with JetStream enabled
24+
on `127.0.0.1:4222` — for example:
25+
26+
```bash
27+
nats-server -js
28+
```
29+
30+
Examples that mix a publisher and subscriber include both in the same file
31+
for convenience.
32+
33+
## Examples
34+
35+
### Basics
36+
- `basics_publish.py` — publish a message to a subject
37+
- `basics_subscribe.py` — subscribe to a subject
38+
39+
### Getting Started
40+
- `getting_started_publish.py` — minimal publisher
41+
- `getting_started_subscribe.py` — minimal subscriber (async + sync)
42+
43+
### Subjects
44+
- `subjects_single_wildcard.py``*` token wildcard subscriptions
45+
- `subjects_multi_wildcard.py``>` tail wildcard subscriptions
46+
- `subjects_monitoring.py` — wire-tap subscription with `>`
47+
48+
### Queue Groups
49+
- `queue_groups_basic.py` — three workers in a queue group
50+
- `queue_groups_dynamic_scaling.py` — add/remove workers at runtime
51+
- `queue_groups_mixed_subscribers.py` — mix of plain subs and queue subs
52+
- `queue_groups_request_reply.py` — load-balanced request/reply
53+
54+
### Request / Reply
55+
- `request_reply_basic.py` — basic request/reply
56+
- `request_reply_calculator.py` — small calculator service
57+
- `request_reply_headers.py` — request/reply with message headers
58+
- `request_reply_multiple_responders.py` — multiple responders, first wins
59+
- `request_reply_no_responders.py` — handling no-responders
60+
- `request_reply_timeout.py` — request with a custom timeout
61+
62+
### JetStream
63+
- `jetstream_basic.py` — create a stream, publish, durable pull consumer

examples/docs/basics_publish.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import asyncio
2+
3+
from nats import client
4+
5+
6+
async def main():
7+
nc = await client.connect("nats://demo.nats.io")
8+
9+
# NATS-DOC-START
10+
# Publish a message to the subject "weather.updates"
11+
await nc.publish("weather.updates", "Temperature: 72°F".encode())
12+
# NATS-DOC-END
13+
14+
await nc.flush()
15+
await nc.close()
16+
17+
18+
if __name__ == "__main__":
19+
asyncio.run(main())

examples/docs/basics_subscribe.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import asyncio
2+
3+
from nats import client
4+
5+
6+
async def main():
7+
nc = await client.connect("nats://demo.nats.io")
8+
9+
# NATS-DOC-START
10+
# Subscribe to 'weather.updates' synchronously
11+
sub = await nc.subscribe("weather.updates")
12+
13+
# Process messages
14+
while True:
15+
try:
16+
msg = await sub.next(timeout=1)
17+
print(f"Received: {msg.data.decode()}")
18+
except TimeoutError:
19+
break
20+
# NATS-DOC-END
21+
22+
await nc.close()
23+
24+
25+
if __name__ == "__main__":
26+
asyncio.run(main())
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import asyncio
2+
3+
from nats import client
4+
5+
6+
# NATS-DOC-START
7+
async def main():
8+
# Connect to NATS demo server
9+
nc = await client.connect("nats://demo.nats.io")
10+
11+
# Publish a message to the subject "hello"
12+
await nc.publish("hello", b"Hello NATS!")
13+
await nc.flush()
14+
15+
print("Message published to hello")
16+
17+
await nc.close()
18+
19+
20+
# NATS-DOC-END
21+
22+
23+
if __name__ == "__main__":
24+
asyncio.run(main())
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import asyncio
2+
3+
from nats import client
4+
5+
6+
# NATS-DOC-START
7+
async def main():
8+
nc = await client.connect("nats://demo.nats.io")
9+
10+
# Asynchronous subscriber - iterate messages in a background task
11+
async_sub = await nc.subscribe("hello")
12+
13+
async def async_handler():
14+
async for msg in async_sub:
15+
print(f"Asynchronous Subscriber Received: {msg.data.decode()}")
16+
17+
asyncio.create_task(async_handler())
18+
19+
# Synchronous subscription
20+
sync_sub = await nc.subscribe("hello")
21+
22+
print("Waiting for message on 'hello'")
23+
24+
# Process messages synchronously
25+
while True:
26+
try:
27+
msg = await sync_sub.next(timeout=1)
28+
print(f"Synchronous Subscriber Received: {msg.data.decode()}")
29+
except TimeoutError:
30+
break
31+
32+
await nc.close()
33+
34+
35+
# NATS-DOC-END
36+
37+
38+
if __name__ == "__main__":
39+
asyncio.run(main())

examples/docs/jetstream_basic.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import asyncio
2+
3+
from nats import client, jetstream
4+
5+
6+
async def main():
7+
# JetStream requires a server with JetStream enabled (demo.nats.io does not).
8+
nc = await client.connect("nats://127.0.0.1:4222")
9+
10+
# NATS-DOC-START
11+
# JetStream context
12+
js = jetstream.new(nc)
13+
14+
# Create a stream that captures any subject under `orders.`
15+
stream = await js.create_stream(name="ORDERS", subjects=["orders.>"], storage="file")
16+
17+
# Publish a few orders
18+
await js.publish("orders.new", b"Order #1001")
19+
await js.publish("orders.new", b"Order #1002")
20+
await js.publish("orders.shipped", b"Order #1001 shipped")
21+
22+
# Create a durable pull consumer that delivers from the beginning
23+
consumer = await stream.create_or_update_consumer(
24+
name="order-processor",
25+
ack_policy="explicit",
26+
)
27+
28+
# Fetch a batch and acknowledge each message
29+
batch = await consumer.fetch(max_messages=3, max_wait=2.0)
30+
async for msg in batch:
31+
print(f"Received on {msg.subject}: {msg.data.decode()}")
32+
await msg.ack()
33+
# NATS-DOC-END
34+
35+
await nc.close()
36+
37+
38+
if __name__ == "__main__":
39+
asyncio.run(main())
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import asyncio
2+
3+
from nats.client import connect
4+
5+
6+
async def main():
7+
client = await connect("nats://localhost:4222")
8+
9+
# NATS-DOC-START
10+
# Publish one order to the orders.created subject. Publishing is
11+
# fire-and-forget: the call hands the message to the server and returns.
12+
order = '{"order_id":"ord_8w2k","customer":"acme-co","total_cents":4200,"ts":"2026-05-22T10:14:22Z"}'
13+
await client.publish("orders.created", order.encode())
14+
# NATS-DOC-END
15+
16+
await client.flush()
17+
await client.close()
18+
19+
20+
if __name__ == "__main__":
21+
asyncio.run(main())

0 commit comments

Comments
 (0)