Skip to content

Commit 716fc8e

Browse files
committed
Initial stream implementation.
1 parent 442de0f commit 716fc8e

File tree

15 files changed

+331
-67
lines changed

15 files changed

+331
-67
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
[package]
22
name = "natsrpy"
3-
version = "0.0.1"
3+
# Don't update version manually. It's set during release workflow.
4+
version = "0.0.0"
45
edition = "2024"
6+
description = "Python NATS client written in Rust"
7+
repository = "https://github.com/taskiq-python/natsrpy"
8+
license-file = "LICENSE"
9+
publish = false
510

611
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
712
[lib]
8-
name = "_inner"
913
crate-type = ["cdylib"]
14+
name = "_inner"
1015

1116
[dependencies]
1217
async-nats = "0.46"

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022-present Pavel Kirilin
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Nats client
2+
3+
This is a client library for [NATS](https://nats.io) written in rust.
4+
5+
Credits for [Intree](https://intree.com) for supporting this project.

pyproject.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
[project]
22
name = "natsrpy"
33
requires-python = ">=3.8"
4+
license-files = ["LICENSE"]
5+
description = "Nats client library written in rust"
6+
readme = "README.md"
47
classifiers = [
58
"Programming Language :: Python :: Implementation :: CPython",
69
"Programming Language :: Python :: Implementation :: PyPy",
@@ -14,6 +17,6 @@ build-backend = "maturin"
1417

1518
[tool.maturin]
1619
bindings = "pyo3"
17-
python-source = "python"
18-
module-name = "natsrpy._inner"
1920
features = ["pyo3/extension-module"]
21+
module-name = "natsrpy._inner"
22+
python-source = "python"

python/natsrpy/_inner/__init__.pyi

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from datetime import timedelta
2+
from typing import Tuple
13
from natsrpy._inner.js import JetStream
24
from natsrpy._inner.message import Message
35

@@ -10,15 +12,15 @@ class Nats:
1012
self,
1113
/,
1214
addrs: list[str] = ["nats://localhost:4222"],
13-
user_and_pass=None,
14-
nkey=None,
15-
token=None,
16-
custom_inbox_prefix=None,
17-
read_buffer_capacity=65535,
18-
sender_capacity=128,
19-
max_reconnects=None,
20-
connection_timeout=5.0,
21-
request_timeout=10.0,
15+
user_and_pass: Tuple[str, str] | None = None,
16+
nkey: str | None = None,
17+
token: str | None = None,
18+
custom_inbox_prefix: str | None = None,
19+
read_buffer_capacity: int = 65535,
20+
sender_capacity: int = 128,
21+
max_reconnects: int | None = None,
22+
connection_timeout: timedelta = timedelta(seconds=5),
23+
request_timeout: timedelta = timedelta(seconds=10),
2224
) -> None: ...
2325
async def startup(self) -> None: ...
2426
async def publish(

python/natsrpy/_inner/js/__init__.pyi

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from natsrpy._inner.js.kv import KeyValue, KVConfig
2+
from natsrpy._inner.js.stream import Stream, StreamConfig
23

34
class JetStream:
45
async def publish(
@@ -10,7 +11,13 @@ class JetStream:
1011
reply: str | None = None,
1112
err_on_disconnect: bool = False,
1213
) -> None: ...
14+
# KV
1315
async def create_kv(self, config: KVConfig) -> KeyValue: ...
1416
async def update_kv(self, config: KVConfig) -> KeyValue: ...
1517
async def get_kv(self, bucket: str) -> KeyValue: ...
1618
async def delete_kv(self, bucket: str) -> bool: ...
19+
# Streams
20+
async def create_stream(self, config: StreamConfig) -> Stream: ...
21+
async def update_stream(self, config: StreamConfig) -> Stream: ...
22+
async def get_stream(self, name: str) -> Stream: ...
23+
async def delete_stream(self, name: str) -> Stream: ...

python/natsrpy/_inner/js/kv.pyi

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ class KVConfig:
4343
) -> None: ...
4444

4545
class KeyValue:
46+
@property
47+
def stream_name(self) -> str: ...
48+
@property
49+
def prefix(self) -> str: ...
50+
@property
51+
def put_prefix(self) -> str | None: ...
52+
@property
53+
def use_jetstream_prefix(self) -> bool: ...
54+
@property
55+
def name(self) -> str: ...
4656
async def put(self, key: str, value: bytes) -> int: ...
4757
async def get(self, key: str) -> bytes | None: ...
4858
async def delete(self, key: str) -> int: ...

python/natsrpy/_inner/js/stream.pyi

Lines changed: 96 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from datetime import timedelta
1+
from datetime import datetime, timedelta
2+
from typing import Any
23

34
class StorageType:
45
FILE: "StorageType"
@@ -90,45 +91,101 @@ class Republish:
9091
) -> None: ...
9192

9293
class StreamConfig:
94+
name: str
95+
subjects: list[str]
96+
max_bytes: int | None
97+
max_messages: int | None
98+
max_messages_per_subject: int | None
99+
discard: DiscardPolicy | None
100+
discard_new_per_subject: bool | None
101+
retention: RetentionPolicy | None
102+
max_consumers: int | None
103+
max_age: timedelta | None
104+
max_message_size: int | None
105+
storage: StorageType | None
106+
num_replicas: int | None
107+
no_ack: bool | None
108+
duplicate_window: timedelta | None
109+
template_owner: str | None
110+
sealed: bool | None
111+
description: str | None
112+
allow_rollup: bool | None
113+
deny_delete: bool | None
114+
deny_purge: bool | None
115+
republish: Republish | None
116+
allow_direct: bool | None
117+
mirror_direct: bool | None
118+
mirror: Source | None
119+
sources: list[Source] | None
120+
metadata: dict[str, str] | None
121+
subject_transform: SubjectTransform | None
122+
compression: Compression | None
123+
consumer_limits: ConsumerLimits | None
124+
first_sequence: int | None
125+
placement: Placement | None
126+
persist_mode: PersistenceMode | None
127+
pause_until: int | None
128+
allow_message_ttl: bool | None
129+
subject_delete_marker_ttl: timedelta | None
130+
allow_atomic_publish: bool | None
131+
allow_message_schedules: bool | None
132+
allow_message_counter: bool | None
133+
93134
def __init__(
94135
self,
95136
name: str,
96-
subjects,
97-
max_bytes=None,
98-
max_messages=None,
99-
max_messages_per_subject=None,
100-
discard=None,
101-
discard_new_per_subject=None,
102-
retention=None,
103-
max_consumers=None,
104-
max_age=None,
105-
max_message_size=None,
106-
storage=None,
107-
num_replicas=None,
108-
no_ack=None,
109-
duplicate_window=None,
110-
template_owner=None,
111-
sealed=None,
112-
description=None,
113-
allow_rollup=None,
114-
deny_delete=None,
115-
deny_purge=None,
116-
republish=None,
117-
allow_direct=None,
118-
mirror_direct=None,
119-
mirror=None,
120-
sources=None,
121-
metadata=None,
122-
subject_transform=None,
123-
compression=None,
124-
consumer_limits=None,
125-
first_sequence=None,
126-
placement=None,
127-
persist_mode=None,
128-
pause_until=None,
129-
allow_message_ttl=None,
130-
subject_delete_marker_ttl=None,
131-
allow_atomic_publish=None,
132-
allow_message_schedules=None,
133-
allow_message_counter=None,
137+
subjects: list[str],
138+
max_bytes: int | None = None,
139+
max_messages: int | None = None,
140+
max_messages_per_subject: int | None = None,
141+
discard: DiscardPolicy | None = None,
142+
discard_new_per_subject: bool | None = None,
143+
retention: RetentionPolicy | None = None,
144+
max_consumers: int | None = None,
145+
max_age: timedelta | None = None,
146+
max_message_size: int | None = None,
147+
storage: StorageType | None = None,
148+
num_replicas: int | None = None,
149+
no_ack: bool | None = None,
150+
duplicate_window: timedelta | None = None,
151+
template_owner: str | None = None,
152+
sealed: bool | None = None,
153+
description: str | None = None,
154+
allow_rollup: bool | None = None,
155+
deny_delete: bool | None = None,
156+
deny_purge: bool | None = None,
157+
republish: Republish | None = None,
158+
allow_direct: bool | None = None,
159+
mirror_direct: bool | None = None,
160+
mirror: Source | None = None,
161+
sources: list[Source] | None = None,
162+
metadata: dict[str, str] | None = None,
163+
subject_transform: SubjectTransform | None = None,
164+
compression: Compression | None = None,
165+
consumer_limits: ConsumerLimits | None = None,
166+
first_sequence: int | None = None,
167+
placement: Placement | None = None,
168+
persist_mode: PersistenceMode | None = None,
169+
pause_until: int | None = None,
170+
allow_message_ttl: bool | None = None,
171+
subject_delete_marker_ttl: timedelta | None = None,
172+
allow_atomic_publish: bool | None = None,
173+
allow_message_schedules: bool | None = None,
174+
allow_message_counter: bool | None = None,
134175
) -> None: ...
176+
177+
class StreamMessage:
178+
subject: str
179+
sequence: int
180+
headers: dict[str, Any]
181+
payload: bytes
182+
time: datetime
183+
184+
class Stream:
185+
async def direct_get(self, sequence: int) -> StreamMessage:
186+
"""
187+
Get direct message from a stream.
188+
189+
Please note, that this method will throw an error
190+
in case of stream being configured without `allow_direct=True`.
191+
"""

python/natsrpy/js/__init__.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
11
from natsrpy._inner.js import JetStream
2+
from natsrpy.js.stream import (
3+
StreamConfig,
4+
Source,
5+
Compression,
6+
ConsumerLimits,
7+
DiscardPolicy,
8+
PersistenceMode,
9+
Placement,
10+
Republish,
11+
RetentionPolicy,
12+
StorageType,
13+
Stream,
14+
SubjectTransform,
15+
External,
16+
StreamMessage,
17+
)
18+
from natsrpy.js.kv import KVConfig, KeyValue
219

3-
__all__ = ["JetStream"]
20+
__all__ = [
21+
"JetStream",
22+
"StreamConfig",
23+
"Source",
24+
"Compression",
25+
"ConsumerLimits",
26+
"DiscardPolicy",
27+
"PersistenceMode",
28+
"Placement",
29+
"Republish",
30+
"RetentionPolicy",
31+
"StorageType",
32+
"Stream",
33+
"SubjectTransform",
34+
"External",
35+
"KVConfig",
36+
"KeyValue",
37+
"StreamMessage",
38+
]

0 commit comments

Comments
 (0)