band-sdk-core 0.2.1.dev2__tar.gz → 0.2.1.dev4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- band_sdk_core-0.2.1.dev4/PKG-INFO +51 -0
- band_sdk_core-0.2.1.dev4/README.md +42 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/Cargo.toml +2 -1
- band_sdk_core-0.2.1.dev4/bindings/python/README.md +42 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/src/lib.rs +1 -1
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_claim_registry.py +14 -14
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_panic_boundary.py +4 -4
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_participant_tracker.py +16 -16
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_retry_tracker.py +6 -6
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_smoke.py +2 -2
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_stub_surface.py +8 -8
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_tracing_propagation.py +10 -10
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/pyproject.toml +3 -2
- band_sdk_core-0.2.1.dev2/PKG-INFO +0 -6
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/Cargo.lock +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/Cargo.toml +0 -0
- /band_sdk_core-0.2.1.dev2/bindings/python/_band_sdk_core.pyi → /band_sdk_core-0.2.1.dev4/bindings/python/band_sdk_core.pyi +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/src/claim_registry.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/src/participant_tracker.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/src/retry_tracker.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/src/tracing_init.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_wheel_ships_typing.py +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/Cargo.toml +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/src/claims.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/src/lib.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/src/participant_tracker.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/src/retry_tracker.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/tests/.gitkeep +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/tests/claims.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/tests/common/mod.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/tests/observability.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/tests/participant_tracker.rs +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/tests/retry_tracker.proptest-regressions +0 -0
- {band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/tests/retry_tracker.rs +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: band-sdk-core
|
|
3
|
+
Version: 0.2.1.dev4
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Summary: Shared Rust core for the Band SDK stack: claims registry, retry tracking, and participant tracking, with Python bindings via PyO3.
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
|
|
9
|
+
# band-sdk-core
|
|
10
|
+
|
|
11
|
+
Shared Rust core for the Band SDK stack, exposed to Python via PyO3: a message claims
|
|
12
|
+
registry, a retry tracker, and a participant tracker, plus an optional tracing bridge.
|
|
13
|
+
See the [repo README](https://github.com/band-ai/band-sdk-core) for the full workspace
|
|
14
|
+
layout and how this binding fits alongside the Rust crates and the Node binding.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install --pre band-sdk-core # currently pre-release only, see Versioning below
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import band_sdk_core as core
|
|
24
|
+
|
|
25
|
+
registry = core.MessageClaimRegistry(max_completed=500)
|
|
26
|
+
with registry.claim("room-1", "msg-1") as acquired:
|
|
27
|
+
if acquired:
|
|
28
|
+
... # handle the message; released automatically on exit, even on exception
|
|
29
|
+
|
|
30
|
+
retry = core.MessageRetryTracker(max_retries=3)
|
|
31
|
+
attempt, exceeded = retry.record_attempt("msg-1")
|
|
32
|
+
|
|
33
|
+
participants = core.ParticipantTracker("room-1")
|
|
34
|
+
participants.add(core.TrackedParticipant(id="user-1", name="Alice"))
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Optional tracing bridge (`RUST_LOG`-filtered, defaults to `info`):
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
with core.Tracing():
|
|
41
|
+
...
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Versioning
|
|
45
|
+
|
|
46
|
+
This package is currently shipping as an ongoing pre-release stream
|
|
47
|
+
(`X.Y.Z.devN`) — install with `pip install --pre band-sdk-core` or pin an exact
|
|
48
|
+
version. A stable release will follow once the API settles.
|
|
49
|
+
|
|
50
|
+
Ships `py.typed` and a `.pyi` stub for full type-checker support.
|
|
51
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# band-sdk-core
|
|
2
|
+
|
|
3
|
+
Shared Rust core for the Band SDK stack, exposed to Python via PyO3: a message claims
|
|
4
|
+
registry, a retry tracker, and a participant tracker, plus an optional tracing bridge.
|
|
5
|
+
See the [repo README](https://github.com/band-ai/band-sdk-core) for the full workspace
|
|
6
|
+
layout and how this binding fits alongside the Rust crates and the Node binding.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install --pre band-sdk-core # currently pre-release only, see Versioning below
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
import band_sdk_core as core
|
|
16
|
+
|
|
17
|
+
registry = core.MessageClaimRegistry(max_completed=500)
|
|
18
|
+
with registry.claim("room-1", "msg-1") as acquired:
|
|
19
|
+
if acquired:
|
|
20
|
+
... # handle the message; released automatically on exit, even on exception
|
|
21
|
+
|
|
22
|
+
retry = core.MessageRetryTracker(max_retries=3)
|
|
23
|
+
attempt, exceeded = retry.record_attempt("msg-1")
|
|
24
|
+
|
|
25
|
+
participants = core.ParticipantTracker("room-1")
|
|
26
|
+
participants.add(core.TrackedParticipant(id="user-1", name="Alice"))
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Optional tracing bridge (`RUST_LOG`-filtered, defaults to `info`):
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
with core.Tracing():
|
|
33
|
+
...
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Versioning
|
|
37
|
+
|
|
38
|
+
This package is currently shipping as an ongoing pre-release stream
|
|
39
|
+
(`X.Y.Z.devN`) — install with `pip install --pre band-sdk-core` or pin an exact
|
|
40
|
+
version. A stable release will follow once the API settles.
|
|
41
|
+
|
|
42
|
+
Ships `py.typed` and a `.pyi` stub for full type-checker support.
|
|
@@ -5,6 +5,7 @@ edition.workspace = true
|
|
|
5
5
|
rust-version.workspace = true
|
|
6
6
|
license.workspace = true
|
|
7
7
|
repository.workspace = true
|
|
8
|
+
readme = "README.md"
|
|
8
9
|
|
|
9
10
|
[lints]
|
|
10
11
|
workspace = true
|
|
@@ -16,7 +17,7 @@ workspace = true
|
|
|
16
17
|
panic-test = []
|
|
17
18
|
|
|
18
19
|
[lib]
|
|
19
|
-
name = "
|
|
20
|
+
name = "band_sdk_core"
|
|
20
21
|
crate-type = ["cdylib"]
|
|
21
22
|
|
|
22
23
|
[dependencies]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# band-sdk-core
|
|
2
|
+
|
|
3
|
+
Shared Rust core for the Band SDK stack, exposed to Python via PyO3: a message claims
|
|
4
|
+
registry, a retry tracker, and a participant tracker, plus an optional tracing bridge.
|
|
5
|
+
See the [repo README](https://github.com/band-ai/band-sdk-core) for the full workspace
|
|
6
|
+
layout and how this binding fits alongside the Rust crates and the Node binding.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install --pre band-sdk-core # currently pre-release only, see Versioning below
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
import band_sdk_core as core
|
|
16
|
+
|
|
17
|
+
registry = core.MessageClaimRegistry(max_completed=500)
|
|
18
|
+
with registry.claim("room-1", "msg-1") as acquired:
|
|
19
|
+
if acquired:
|
|
20
|
+
... # handle the message; released automatically on exit, even on exception
|
|
21
|
+
|
|
22
|
+
retry = core.MessageRetryTracker(max_retries=3)
|
|
23
|
+
attempt, exceeded = retry.record_attempt("msg-1")
|
|
24
|
+
|
|
25
|
+
participants = core.ParticipantTracker("room-1")
|
|
26
|
+
participants.add(core.TrackedParticipant(id="user-1", name="Alice"))
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Optional tracing bridge (`RUST_LOG`-filtered, defaults to `info`):
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
with core.Tracing():
|
|
33
|
+
...
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Versioning
|
|
37
|
+
|
|
38
|
+
This package is currently shipping as an ongoing pre-release stream
|
|
39
|
+
(`X.Y.Z.devN`) — install with `pip install --pre band-sdk-core` or pin an exact
|
|
40
|
+
version. A stable release will follow once the API settles.
|
|
41
|
+
|
|
42
|
+
Ships `py.typed` and a `.pyi` stub for full type-checker support.
|
|
@@ -18,7 +18,7 @@ fn debug_panic() {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
#[pymodule]
|
|
21
|
-
fn
|
|
21
|
+
fn band_sdk_core(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
22
22
|
m.add_class::<claim_registry::MessageClaimRegistry>()?;
|
|
23
23
|
m.add_class::<claim_registry::ClaimGuard>()?;
|
|
24
24
|
m.add_class::<retry_tracker::MessageRetryTracker>()?;
|
{band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_claim_registry.py
RENAMED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import band_sdk_core
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def test_try_claim_blocks_a_second_owner_until_released():
|
|
7
|
-
registry =
|
|
7
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
8
8
|
|
|
9
9
|
assert registry._try_claim("room-1", "msg-1") is True
|
|
10
10
|
assert registry._try_claim("room-1", "msg-1") is False
|
|
@@ -14,14 +14,14 @@ def test_try_claim_blocks_a_second_owner_until_released():
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def test_try_claim_accepts_an_optional_correlation_id_without_error():
|
|
17
|
-
registry =
|
|
17
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
18
18
|
|
|
19
19
|
assert registry._try_claim("room-1", "msg-1", correlation_id="corr-abc") is True
|
|
20
20
|
registry._release("room-1", "msg-1", correlation_id="corr-abc")
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def test_max_completed_defaults_without_an_explicit_argument():
|
|
24
|
-
registry =
|
|
24
|
+
registry = band_sdk_core.MessageClaimRegistry()
|
|
25
25
|
|
|
26
26
|
for i in range(501):
|
|
27
27
|
registry.remember_completed("room-1", f"msg-{i}")
|
|
@@ -31,7 +31,7 @@ def test_max_completed_defaults_without_an_explicit_argument():
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def test_completed_cache_is_scoped_per_room_and_respects_its_cap():
|
|
34
|
-
registry =
|
|
34
|
+
registry = band_sdk_core.MessageClaimRegistry(1)
|
|
35
35
|
|
|
36
36
|
registry.remember_completed("room-1", "msg-1")
|
|
37
37
|
registry.remember_completed("room-1", "msg-2") # evicts msg-1, cap is 1
|
|
@@ -41,7 +41,7 @@ def test_completed_cache_is_scoped_per_room_and_respects_its_cap():
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
def test_ack_pending_lifecycle():
|
|
44
|
-
registry =
|
|
44
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
45
45
|
|
|
46
46
|
assert registry.is_ack_pending("room-1", "msg-1") is False
|
|
47
47
|
registry.remember_ack_pending("room-1", "msg-1")
|
|
@@ -56,7 +56,7 @@ def test_ack_pending_lifecycle():
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
def test_discard_ack_pending_gives_up_and_resets_the_retry_count():
|
|
59
|
-
registry =
|
|
59
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
60
60
|
registry.remember_ack_pending("room-1", "msg-1")
|
|
61
61
|
registry.record_ack_retry("room-1", "msg-1")
|
|
62
62
|
|
|
@@ -67,7 +67,7 @@ def test_discard_ack_pending_gives_up_and_resets_the_retry_count():
|
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
def test_discard_room_forgets_claims_acks_and_the_completed_cache():
|
|
70
|
-
registry =
|
|
70
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
71
71
|
registry.remember_completed("room-1", "done")
|
|
72
72
|
registry._try_claim("room-1", "stranded")
|
|
73
73
|
registry.remember_ack_pending("room-1", "owed")
|
|
@@ -80,7 +80,7 @@ def test_discard_room_forgets_claims_acks_and_the_completed_cache():
|
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
def test_claim_guard_releases_on_normal_exit():
|
|
83
|
-
registry =
|
|
83
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
84
84
|
|
|
85
85
|
with registry.claim("room-1", "msg-1") as acquired:
|
|
86
86
|
assert acquired is True
|
|
@@ -89,7 +89,7 @@ def test_claim_guard_releases_on_normal_exit():
|
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
def test_claim_guard_releases_even_when_the_body_raises():
|
|
92
|
-
registry =
|
|
92
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
93
93
|
|
|
94
94
|
try:
|
|
95
95
|
with registry.claim("room-1", "msg-1") as acquired:
|
|
@@ -102,7 +102,7 @@ def test_claim_guard_releases_even_when_the_body_raises():
|
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
def test_claim_guard_reports_contention_and_does_not_release_the_owner():
|
|
105
|
-
registry =
|
|
105
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
106
106
|
assert registry._try_claim("room-1", "msg-1") is True
|
|
107
107
|
|
|
108
108
|
with registry.claim("room-1", "msg-1") as acquired:
|
|
@@ -113,7 +113,7 @@ def test_claim_guard_reports_contention_and_does_not_release_the_owner():
|
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
def test_claim_guard_rejects_a_second_enter_instead_of_losing_track_of_the_first():
|
|
116
|
-
registry =
|
|
116
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
117
117
|
guard = registry.claim("room-1", "msg-1")
|
|
118
118
|
|
|
119
119
|
guard.__enter__()
|
|
@@ -128,7 +128,7 @@ def test_claim_guard_rejects_a_second_enter_instead_of_losing_track_of_the_first
|
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
def test_claim_guard_exit_is_a_no_op_after_the_first_release():
|
|
131
|
-
registry =
|
|
131
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
132
132
|
guard = registry.claim("room-1", "msg-1")
|
|
133
133
|
guard.__enter__()
|
|
134
134
|
guard.__exit__(None, None, None)
|
|
@@ -142,7 +142,7 @@ def test_claim_guard_exit_is_a_no_op_after_the_first_release():
|
|
|
142
142
|
|
|
143
143
|
|
|
144
144
|
def test_claim_guard_accepts_an_optional_correlation_id_without_error():
|
|
145
|
-
registry =
|
|
145
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
146
146
|
|
|
147
147
|
with registry.claim("room-1", "msg-1", correlation_id="corr-abc") as acquired:
|
|
148
148
|
assert acquired is True
|
{band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_panic_boundary.py
RENAMED
|
@@ -8,17 +8,17 @@ skip rather than fail.
|
|
|
8
8
|
|
|
9
9
|
import pytest
|
|
10
10
|
|
|
11
|
-
import
|
|
11
|
+
import band_sdk_core
|
|
12
12
|
|
|
13
13
|
pytestmark = pytest.mark.skipif(
|
|
14
|
-
not hasattr(
|
|
14
|
+
not hasattr(band_sdk_core, "debug_panic"),
|
|
15
15
|
reason="built without --features panic-test",
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def test_rust_panic_surfaces_as_catchable_panic_exception():
|
|
20
20
|
with pytest.raises(BaseException, match="deliberate panic") as excinfo:
|
|
21
|
-
|
|
21
|
+
band_sdk_core.debug_panic()
|
|
22
22
|
|
|
23
23
|
assert type(excinfo.value).__name__ == "PanicException"
|
|
24
24
|
|
|
@@ -29,6 +29,6 @@ def test_panic_exception_is_a_base_exception_not_an_exception():
|
|
|
29
29
|
# swallow it. Pinned on purpose: handler code relying on `except
|
|
30
30
|
# Exception` must know a Rust panic flies past it.
|
|
31
31
|
with pytest.raises(BaseException) as excinfo:
|
|
32
|
-
|
|
32
|
+
band_sdk_core.debug_panic()
|
|
33
33
|
|
|
34
34
|
assert not isinstance(excinfo.value, Exception)
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import
|
|
1
|
+
import band_sdk_core
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
def test_room_id_returns_the_configured_room():
|
|
5
|
-
tracker =
|
|
5
|
+
tracker = band_sdk_core.ParticipantTracker("room-1")
|
|
6
6
|
assert tracker.room_id() == "room-1"
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def test_add_returns_true_and_stores_the_participant():
|
|
10
|
-
tracker =
|
|
11
|
-
participant =
|
|
10
|
+
tracker = band_sdk_core.ParticipantTracker("room-1")
|
|
11
|
+
participant = band_sdk_core.TrackedParticipant(id="p1", name="Ada")
|
|
12
12
|
|
|
13
13
|
assert tracker.add(participant) is True
|
|
14
14
|
assert [p.id for p in tracker.participants()] == ["p1"]
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def test_tracked_participant_equality_compares_fields_not_identity():
|
|
18
|
-
a =
|
|
19
|
-
b =
|
|
18
|
+
a = band_sdk_core.TrackedParticipant(id="p1", name="Ada")
|
|
19
|
+
b = band_sdk_core.TrackedParticipant(id="p1", name="Ada")
|
|
20
20
|
|
|
21
21
|
assert a == b
|
|
22
|
-
assert a !=
|
|
22
|
+
assert a != band_sdk_core.TrackedParticipant(id="p2", name="Ada")
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def test_add_rejects_a_duplicate_id_without_storing_it_twice():
|
|
26
|
-
tracker =
|
|
27
|
-
tracker.add(
|
|
26
|
+
tracker = band_sdk_core.ParticipantTracker("room-1")
|
|
27
|
+
tracker.add(band_sdk_core.TrackedParticipant(id="p1"))
|
|
28
28
|
|
|
29
|
-
assert tracker.add(
|
|
29
|
+
assert tracker.add(band_sdk_core.TrackedParticipant(id="p1")) is False
|
|
30
30
|
assert len(tracker.participants()) == 1
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def test_remove_reports_whether_a_participant_was_actually_present():
|
|
34
|
-
tracker =
|
|
35
|
-
tracker.add(
|
|
34
|
+
tracker = band_sdk_core.ParticipantTracker("room-1")
|
|
35
|
+
tracker.add(band_sdk_core.TrackedParticipant(id="p1"))
|
|
36
36
|
|
|
37
37
|
assert tracker.remove("p1") is True
|
|
38
38
|
assert tracker.remove("p1") is False
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def test_changed_is_true_until_the_current_roster_is_marked_sent():
|
|
42
|
-
tracker =
|
|
43
|
-
tracker.add(
|
|
42
|
+
tracker = band_sdk_core.ParticipantTracker("room-1")
|
|
43
|
+
tracker.add(band_sdk_core.TrackedParticipant(id="p1"))
|
|
44
44
|
|
|
45
45
|
assert tracker.changed() is True
|
|
46
46
|
tracker.mark_sent()
|
|
@@ -48,10 +48,10 @@ def test_changed_is_true_until_the_current_roster_is_marked_sent():
|
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
def test_set_loaded_replaces_the_roster_and_flips_the_loaded_flag():
|
|
51
|
-
tracker =
|
|
51
|
+
tracker = band_sdk_core.ParticipantTracker("room-1")
|
|
52
52
|
assert tracker.is_loaded() is False
|
|
53
53
|
|
|
54
|
-
tracker.set_loaded([
|
|
54
|
+
tracker.set_loaded([band_sdk_core.TrackedParticipant(id="p1")])
|
|
55
55
|
|
|
56
56
|
assert tracker.is_loaded() is True
|
|
57
57
|
assert [p.id for p in tracker.participants()] == ["p1"]
|
{band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_retry_tracker.py
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import band_sdk_core
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
def test_default_tracks_a_budget_of_one_retry():
|
|
5
|
-
tracker =
|
|
5
|
+
tracker = band_sdk_core.MessageRetryTracker()
|
|
6
6
|
assert tracker.max_retries() == 1
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def test_tracks_attempts_and_exceeds_budget():
|
|
10
|
-
tracker =
|
|
10
|
+
tracker = band_sdk_core.MessageRetryTracker(2, 100)
|
|
11
11
|
|
|
12
12
|
assert tracker.record_attempt("msg-1") == (1, False)
|
|
13
13
|
assert tracker.record_attempt("msg-1") == (2, False)
|
|
@@ -18,7 +18,7 @@ def test_tracks_attempts_and_exceeds_budget():
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def test_mark_success_resets_the_attempt_count():
|
|
21
|
-
tracker =
|
|
21
|
+
tracker = band_sdk_core.MessageRetryTracker(3, 100)
|
|
22
22
|
tracker.record_attempt("msg-1")
|
|
23
23
|
tracker.record_attempt("msg-1")
|
|
24
24
|
|
|
@@ -28,7 +28,7 @@ def test_mark_success_resets_the_attempt_count():
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
def test_discard_attempt_decrements_rather_than_clears():
|
|
31
|
-
tracker =
|
|
31
|
+
tracker = band_sdk_core.MessageRetryTracker(5, 100)
|
|
32
32
|
tracker.record_attempt("msg-1")
|
|
33
33
|
tracker.record_attempt("msg-1")
|
|
34
34
|
tracker.record_attempt("msg-1")
|
|
@@ -39,6 +39,6 @@ def test_discard_attempt_decrements_rather_than_clears():
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def test_mark_permanently_failed_bypasses_the_retry_budget_entirely():
|
|
42
|
-
tracker =
|
|
42
|
+
tracker = band_sdk_core.MessageRetryTracker(100, 100)
|
|
43
43
|
tracker.mark_permanently_failed("msg-1")
|
|
44
44
|
assert tracker.is_permanently_failed("msg-1") is True
|
{band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/tests/test_stub_surface.py
RENAMED
|
@@ -13,7 +13,7 @@ from pathlib import Path
|
|
|
13
13
|
|
|
14
14
|
import pytest
|
|
15
15
|
|
|
16
|
-
import
|
|
16
|
+
import band_sdk_core
|
|
17
17
|
|
|
18
18
|
# Feature-gated test hooks (built only with `--features panic-test`) are
|
|
19
19
|
# deliberately absent from the stub: they never ship in a release artifact.
|
|
@@ -21,12 +21,12 @@ FEATURE_GATED = {"debug_panic"}
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def _load_stub():
|
|
24
|
-
module_file = getattr(
|
|
24
|
+
module_file = getattr(band_sdk_core, "__file__", None)
|
|
25
25
|
candidates = []
|
|
26
26
|
if module_file:
|
|
27
27
|
candidates.extend(Path(module_file).parent.glob("*.pyi"))
|
|
28
28
|
# maturin-develop / repo checkout fallback.
|
|
29
|
-
candidates.append(Path(__file__).parent.parent / "
|
|
29
|
+
candidates.append(Path(__file__).parent.parent / "band_sdk_core.pyi")
|
|
30
30
|
for candidate in candidates:
|
|
31
31
|
if candidate.exists():
|
|
32
32
|
return ast.parse(candidate.read_text())
|
|
@@ -42,10 +42,10 @@ STUB_FUNCTIONS = {
|
|
|
42
42
|
|
|
43
43
|
def _module_surface():
|
|
44
44
|
classes, functions = set(), set()
|
|
45
|
-
for name in dir(
|
|
45
|
+
for name in dir(band_sdk_core):
|
|
46
46
|
if name.startswith("__") or name in FEATURE_GATED:
|
|
47
47
|
continue
|
|
48
|
-
obj = getattr(
|
|
48
|
+
obj = getattr(band_sdk_core, name)
|
|
49
49
|
if inspect.ismodule(obj):
|
|
50
50
|
continue # the extension exposes a self-reference attribute
|
|
51
51
|
(classes if inspect.isclass(obj) else functions).add(name)
|
|
@@ -76,7 +76,7 @@ def _stub_attributes(cls_node):
|
|
|
76
76
|
|
|
77
77
|
@pytest.mark.parametrize("class_name", sorted(STUB_CLASSES))
|
|
78
78
|
def test_every_stub_declared_member_exists(class_name):
|
|
79
|
-
cls = getattr(
|
|
79
|
+
cls = getattr(band_sdk_core, class_name)
|
|
80
80
|
node = STUB_CLASSES[class_name]
|
|
81
81
|
|
|
82
82
|
for method_name in _stub_methods(node):
|
|
@@ -87,7 +87,7 @@ def test_every_stub_declared_member_exists(class_name):
|
|
|
87
87
|
|
|
88
88
|
@pytest.mark.parametrize("class_name", sorted(STUB_CLASSES))
|
|
89
89
|
def test_every_runtime_public_member_is_declared_in_the_stub(class_name):
|
|
90
|
-
cls = getattr(
|
|
90
|
+
cls = getattr(band_sdk_core, class_name)
|
|
91
91
|
node = STUB_CLASSES[class_name]
|
|
92
92
|
declared = set(_stub_methods(node)) | _stub_attributes(node)
|
|
93
93
|
|
|
@@ -150,7 +150,7 @@ def _assert_signatures_match(qualname, stub_params, runtime_params):
|
|
|
150
150
|
|
|
151
151
|
@pytest.mark.parametrize("class_name", sorted(STUB_CLASSES))
|
|
152
152
|
def test_method_signatures_match_the_stub(class_name):
|
|
153
|
-
cls = getattr(
|
|
153
|
+
cls = getattr(band_sdk_core, class_name)
|
|
154
154
|
node = STUB_CLASSES[class_name]
|
|
155
155
|
|
|
156
156
|
compared = 0
|
|
@@ -12,13 +12,13 @@ import os
|
|
|
12
12
|
import subprocess
|
|
13
13
|
import sys
|
|
14
14
|
|
|
15
|
-
import
|
|
15
|
+
import band_sdk_core
|
|
16
16
|
|
|
17
17
|
SCRIPT = """
|
|
18
|
-
import
|
|
18
|
+
import band_sdk_core
|
|
19
19
|
|
|
20
|
-
with
|
|
21
|
-
registry =
|
|
20
|
+
with band_sdk_core.Tracing():
|
|
21
|
+
registry = band_sdk_core.MessageClaimRegistry(10)
|
|
22
22
|
registry._try_claim("room-e2e", "message-e2e", correlation_id="corr-e2e")
|
|
23
23
|
"""
|
|
24
24
|
|
|
@@ -52,11 +52,11 @@ def test_default_filter_is_info_when_rust_log_is_unset():
|
|
|
52
52
|
# default too), while the debug-level lifecycle chatter stays off. An
|
|
53
53
|
# error-only default would make a host conclude the telemetry is broken.
|
|
54
54
|
script = """
|
|
55
|
-
import
|
|
55
|
+
import band_sdk_core
|
|
56
56
|
|
|
57
|
-
with
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
with band_sdk_core.Tracing():
|
|
58
|
+
band_sdk_core.MessageClaimRegistry(10)._try_claim("room-default", "message-default")
|
|
59
|
+
band_sdk_core.MessageRetryTracker().mark_permanently_failed("message-default")
|
|
60
60
|
"""
|
|
61
61
|
env = {key: value for key, value in os.environ.items() if key != "RUST_LOG"}
|
|
62
62
|
result = subprocess.run(
|
|
@@ -90,7 +90,7 @@ def test_rust_log_filter_silences_claim_telemetry():
|
|
|
90
90
|
def test_tracing_can_be_entered_more_than_once_in_one_process():
|
|
91
91
|
# The subscriber is global and installed once per process, so a second
|
|
92
92
|
# entry has nothing left to install — it must no-op rather than raise.
|
|
93
|
-
with
|
|
93
|
+
with band_sdk_core.Tracing():
|
|
94
94
|
pass
|
|
95
|
-
with
|
|
95
|
+
with band_sdk_core.Tracing():
|
|
96
96
|
pass
|
|
@@ -5,10 +5,11 @@ build-backend = "maturin"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "band-sdk-core"
|
|
7
7
|
description = "Shared Rust core for the Band SDK stack: claims registry, retry tracking, and participant tracking, with Python bindings via PyO3."
|
|
8
|
-
|
|
8
|
+
readme = { file = "README.md", content-type = "text/markdown" }
|
|
9
|
+
version = "0.2.1.dev4"
|
|
9
10
|
requires-python = ">=3.11"
|
|
10
11
|
classifiers = ["Development Status :: 3 - Alpha"]
|
|
11
12
|
|
|
12
13
|
[tool.maturin]
|
|
13
|
-
module-name = "
|
|
14
|
+
module-name = "band_sdk_core"
|
|
14
15
|
manifest-path = "bindings/python/Cargo.toml"
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: band-sdk-core
|
|
3
|
-
Version: 0.2.1.dev2
|
|
4
|
-
Classifier: Development Status :: 3 - Alpha
|
|
5
|
-
Summary: Shared Rust core for the Band SDK stack: claims registry, retry tracking, and participant tracking, with Python bindings via PyO3.
|
|
6
|
-
Requires-Python: >=3.11
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/bindings/python/src/participant_tracker.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/src/participant_tracker.rs
RENAMED
|
File without changes
|
{band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/src/retry_tracker.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/tests/common/mod.rs
RENAMED
|
File without changes
|
{band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/tests/observability.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{band_sdk_core-0.2.1.dev2 → band_sdk_core-0.2.1.dev4}/crates/core-runtime/tests/retry_tracker.rs
RENAMED
|
File without changes
|