meta-memcache-socket 0.2.0b2__tar.gz → 0.3.0__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.
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/.github/workflows/CI.yml +5 -5
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/.github/workflows/tests.yml +1 -1
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/Cargo.lock +1 -1
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/Cargo.toml +1 -1
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/PKG-INFO +1 -1
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/README.md +20 -3
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/meta_memcache_socket.pyi +45 -22
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/encode_key.rs +7 -4
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/request_flags.rs +101 -23
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/request_flags_tests.rs +167 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/tests/test_memcache_socket.py +49 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/.github/pull_request_template.md +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/.gitignore +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/LICENSE +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/pyproject.toml +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/constants.rs +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/impl_build_cmd.rs +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/impl_build_cmd_tests.rs +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/impl_parse_header.rs +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/impl_parse_header_tests.rs +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/lib.rs +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/memcache_socket.rs +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/response_flags.rs +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/response_flags_tests.rs +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/src/response_types.rs +0 -0
- {meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/tests/test_response_types.py +0 -0
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
with:
|
|
43
43
|
python-version: 3.x
|
|
44
44
|
- name: Build wheels
|
|
45
|
-
uses: PyO3/maturin-action@v1
|
|
45
|
+
uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
|
|
46
46
|
with:
|
|
47
47
|
target: ${{ matrix.platform.target }}
|
|
48
48
|
args: --release --out dist --find-interpreter
|
|
@@ -73,7 +73,7 @@ jobs:
|
|
|
73
73
|
with:
|
|
74
74
|
python-version: 3.x
|
|
75
75
|
- name: Build wheels
|
|
76
|
-
uses: PyO3/maturin-action@v1
|
|
76
|
+
uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
|
|
77
77
|
with:
|
|
78
78
|
target: ${{ matrix.platform.target }}
|
|
79
79
|
args: --release --out dist --find-interpreter
|
|
@@ -100,7 +100,7 @@ jobs:
|
|
|
100
100
|
with:
|
|
101
101
|
python-version: 3.x
|
|
102
102
|
- name: Build wheels
|
|
103
|
-
uses: PyO3/maturin-action@v1
|
|
103
|
+
uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
|
|
104
104
|
with:
|
|
105
105
|
target: ${{ matrix.platform.target }}
|
|
106
106
|
args: --release --out dist --find-interpreter
|
|
@@ -116,7 +116,7 @@ jobs:
|
|
|
116
116
|
steps:
|
|
117
117
|
- uses: actions/checkout@v6
|
|
118
118
|
- name: Build sdist
|
|
119
|
-
uses: PyO3/maturin-action@v1
|
|
119
|
+
uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
|
|
120
120
|
with:
|
|
121
121
|
command: sdist
|
|
122
122
|
args: --out dist
|
|
@@ -146,7 +146,7 @@ jobs:
|
|
|
146
146
|
subject-path: 'wheels-*/*'
|
|
147
147
|
- name: Install uv
|
|
148
148
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
|
149
|
-
uses: astral-sh/setup-uv@v7
|
|
149
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
150
150
|
- name: Publish to PyPI
|
|
151
151
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
|
152
152
|
run: uv publish 'wheels-*/*'
|
|
@@ -26,7 +26,7 @@ jobs:
|
|
|
26
26
|
- uses: actions/setup-python@v5
|
|
27
27
|
with:
|
|
28
28
|
python-version: "3.x"
|
|
29
|
-
- uses: astral-sh/setup-uv@v4
|
|
29
|
+
- uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4.2.0
|
|
30
30
|
- name: Build and install extension
|
|
31
31
|
run: uv run --with maturin maturin develop
|
|
32
32
|
- name: Run Python tests
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meta-memcache-socket
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -29,7 +29,7 @@ meta-memcache-socket-py/
|
|
|
29
29
|
│ ├── lib.rs # PyO3 module entry — exports classes, functions, constants
|
|
30
30
|
│ ├── constants.rs # Protocol constants (response codes, set modes, NOOP, ENDL)
|
|
31
31
|
│ ├── memcache_socket.rs # MemcacheSocket class — socket I/O, buffering, GIL management
|
|
32
|
-
│ ├── request_flags.rs # RequestFlags class —
|
|
32
|
+
│ ├── request_flags.rs # RequestFlags class — immutable flags for building commands
|
|
33
33
|
│ ├── response_flags.rs # ResponseFlags class — immutable flags parsed from responses
|
|
34
34
|
│ ├── response_types.rs # Response type classes (Value, Success, Miss, NotStored, Conflict)
|
|
35
35
|
│ ├── impl_build_cmd.rs # Command builder — key validation, base64, flag encoding
|
|
@@ -175,7 +175,7 @@ flags.opaque # Optional[bytes] — echoed opaque data (O)
|
|
|
175
175
|
|
|
176
176
|
### RequestFlags
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
Immutable container for flags sent with commands.
|
|
179
179
|
|
|
180
180
|
```python
|
|
181
181
|
from meta_memcache_socket import RequestFlags
|
|
@@ -205,11 +205,28 @@ flags = RequestFlags(
|
|
|
205
205
|
opaque=None, # O — opaque data echoed back
|
|
206
206
|
mode=None, # M — operation mode (set/arithmetic)
|
|
207
207
|
)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The flags are immutable, so they can be reused safely across threads when
|
|
211
|
+
calling meta commands. Internal layers migth need to mutate flags
|
|
212
|
+
(content id, reduce ttl, etc...) and will mutate them use replace() to create
|
|
213
|
+
modified copies when needed.
|
|
214
|
+
|
|
215
|
+
If you need to change flags on a existing RequestFlags, use the `replace()` method:
|
|
208
216
|
|
|
209
|
-
|
|
217
|
+
```python
|
|
218
|
+
new_flags = flags.replace(return_ttl=True, cache_ttl=600) # -> RequestFlags
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
You can also encode the flags into a byte string for command building, showing
|
|
222
|
+
exactly what will be sent on the wire:
|
|
223
|
+
|
|
224
|
+
```python
|
|
210
225
|
flags.to_bytes() # -> bytes (encoded flag string)
|
|
211
226
|
```
|
|
212
227
|
|
|
228
|
+
For debugging purposes, stringifying it shows the flags in a human-readable format.
|
|
229
|
+
|
|
213
230
|
### Command builders
|
|
214
231
|
|
|
215
232
|
Convenience functions that build meta-protocol command byte strings.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import socket
|
|
2
|
-
from typing import Any, Optional, Tuple, Union
|
|
2
|
+
from typing import Any, Final, Optional, Tuple, Union
|
|
3
3
|
|
|
4
4
|
RESPONSE_VALUE: int # 1 - VALUE (VA)
|
|
5
5
|
RESPONSE_SUCCESS: int # 2 - SUCCESS (OK or HD)
|
|
@@ -56,26 +56,26 @@ class RequestFlags:
|
|
|
56
56
|
* mode: The mode to use when storing the value in the cache. See SET_MODE_* and MA_MODE_* constants
|
|
57
57
|
"""
|
|
58
58
|
|
|
59
|
-
no_reply: bool
|
|
60
|
-
return_client_flag: bool
|
|
61
|
-
return_cas_token: bool
|
|
62
|
-
return_value: bool
|
|
63
|
-
return_ttl: bool
|
|
64
|
-
return_size: bool
|
|
65
|
-
return_last_access: bool
|
|
66
|
-
return_fetched: bool
|
|
67
|
-
return_key: bool
|
|
68
|
-
no_update_lru: bool
|
|
69
|
-
mark_stale: bool
|
|
70
|
-
cache_ttl: Optional[int]
|
|
71
|
-
recache_ttl: Optional[int]
|
|
72
|
-
vivify_on_miss_ttl: Optional[int]
|
|
73
|
-
client_flag: Optional[int]
|
|
74
|
-
ma_initial_value: Optional[int]
|
|
75
|
-
ma_delta_value: Optional[int]
|
|
76
|
-
cas_token: Optional[int]
|
|
77
|
-
opaque: Optional[bytes]
|
|
78
|
-
mode: Optional[int]
|
|
59
|
+
no_reply: Final[bool]
|
|
60
|
+
return_client_flag: Final[bool]
|
|
61
|
+
return_cas_token: Final[bool]
|
|
62
|
+
return_value: Final[bool]
|
|
63
|
+
return_ttl: Final[bool]
|
|
64
|
+
return_size: Final[bool]
|
|
65
|
+
return_last_access: Final[bool]
|
|
66
|
+
return_fetched: Final[bool]
|
|
67
|
+
return_key: Final[bool]
|
|
68
|
+
no_update_lru: Final[bool]
|
|
69
|
+
mark_stale: Final[bool]
|
|
70
|
+
cache_ttl: Final[Optional[int]]
|
|
71
|
+
recache_ttl: Final[Optional[int]]
|
|
72
|
+
vivify_on_miss_ttl: Final[Optional[int]]
|
|
73
|
+
client_flag: Final[Optional[int]]
|
|
74
|
+
ma_initial_value: Final[Optional[int]]
|
|
75
|
+
ma_delta_value: Final[Optional[int]]
|
|
76
|
+
cas_token: Final[Optional[int]]
|
|
77
|
+
opaque: Final[Optional[bytes]]
|
|
78
|
+
mode: Final[Optional[int]]
|
|
79
79
|
|
|
80
80
|
def __init__(
|
|
81
81
|
self,
|
|
@@ -101,7 +101,30 @@ class RequestFlags:
|
|
|
101
101
|
opaque: Optional[bytes] = None,
|
|
102
102
|
mode: Optional[int] = None,
|
|
103
103
|
) -> None: ...
|
|
104
|
-
def
|
|
104
|
+
def replace(
|
|
105
|
+
self,
|
|
106
|
+
*,
|
|
107
|
+
no_reply: Optional[bool] = None,
|
|
108
|
+
return_client_flag: Optional[bool] = None,
|
|
109
|
+
return_cas_token: Optional[bool] = None,
|
|
110
|
+
return_value: Optional[bool] = None,
|
|
111
|
+
return_ttl: Optional[bool] = None,
|
|
112
|
+
return_size: Optional[bool] = None,
|
|
113
|
+
return_last_access: Optional[bool] = None,
|
|
114
|
+
return_fetched: Optional[bool] = None,
|
|
115
|
+
return_key: Optional[bool] = None,
|
|
116
|
+
no_update_lru: Optional[bool] = None,
|
|
117
|
+
mark_stale: Optional[bool] = None,
|
|
118
|
+
cache_ttl: Optional[int] = None,
|
|
119
|
+
recache_ttl: Optional[int] = None,
|
|
120
|
+
vivify_on_miss_ttl: Optional[int] = None,
|
|
121
|
+
client_flag: Optional[int] = None,
|
|
122
|
+
ma_initial_value: Optional[int] = None,
|
|
123
|
+
ma_delta_value: Optional[int] = None,
|
|
124
|
+
cas_token: Optional[int] = None,
|
|
125
|
+
opaque: Optional[bytes] = None,
|
|
126
|
+
mode: Optional[int] = None,
|
|
127
|
+
) -> "RequestFlags": ...
|
|
105
128
|
def to_bytes(self) -> bytes: ...
|
|
106
129
|
def __str__(self) -> str: ...
|
|
107
130
|
|
|
@@ -3,6 +3,7 @@ use blake2::Blake2bVar;
|
|
|
3
3
|
use blake2::digest::{Update, VariableOutput};
|
|
4
4
|
use pyo3::exceptions::PyValueError;
|
|
5
5
|
use pyo3::prelude::*;
|
|
6
|
+
use pyo3::types::{PyBytes, PyString};
|
|
6
7
|
|
|
7
8
|
/// Max raw key size before hashing. Binary keys get base64-encoded (4/3 expansion),
|
|
8
9
|
/// so the threshold is 250 * 3 / 4 ≈ 187.
|
|
@@ -59,10 +60,12 @@ pub fn encode_key(data: &[u8]) -> Option<EncodedKey> {
|
|
|
59
60
|
|
|
60
61
|
/// Extract a key from a Python object. Accepts str (UTF-8) or bytes.
|
|
61
62
|
pub fn extract_key<'py>(ob: &'py Bound<'py, PyAny>) -> PyResult<&'py [u8]> {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
Ok(
|
|
63
|
+
// Use `cast` instead of `extract` — turning `PyDowncastError` into `PyErr` is costly,
|
|
64
|
+
// and we only care about the success path here.
|
|
65
|
+
if let Ok(s) = ob.cast::<PyString>() {
|
|
66
|
+
Ok(s.to_str()?.as_bytes())
|
|
67
|
+
} else if let Ok(b) = ob.cast::<PyBytes>() {
|
|
68
|
+
Ok(b.as_bytes())
|
|
66
69
|
} else {
|
|
67
70
|
Err(PyValueError::new_err("key must be str or bytes"))
|
|
68
71
|
}
|
|
@@ -3,48 +3,48 @@ use pyo3::types::PyBytes;
|
|
|
3
3
|
|
|
4
4
|
use crate::{MA_MODE_INC, SET_MODE_SET};
|
|
5
5
|
|
|
6
|
-
#[pyclass(eq, skip_from_py_object)]
|
|
6
|
+
#[pyclass(eq, skip_from_py_object, frozen)]
|
|
7
7
|
#[derive(Clone, Debug, PartialEq)]
|
|
8
8
|
pub struct RequestFlags {
|
|
9
|
-
#[pyo3(get
|
|
9
|
+
#[pyo3(get)]
|
|
10
10
|
no_reply: bool,
|
|
11
|
-
#[pyo3(get
|
|
11
|
+
#[pyo3(get)]
|
|
12
12
|
return_client_flag: bool,
|
|
13
|
-
#[pyo3(get
|
|
13
|
+
#[pyo3(get)]
|
|
14
14
|
return_cas_token: bool,
|
|
15
|
-
#[pyo3(get
|
|
15
|
+
#[pyo3(get)]
|
|
16
16
|
return_value: bool,
|
|
17
|
-
#[pyo3(get
|
|
17
|
+
#[pyo3(get)]
|
|
18
18
|
return_ttl: bool,
|
|
19
|
-
#[pyo3(get
|
|
19
|
+
#[pyo3(get)]
|
|
20
20
|
return_size: bool,
|
|
21
|
-
#[pyo3(get
|
|
21
|
+
#[pyo3(get)]
|
|
22
22
|
return_last_access: bool,
|
|
23
|
-
#[pyo3(get
|
|
23
|
+
#[pyo3(get)]
|
|
24
24
|
return_fetched: bool,
|
|
25
|
-
#[pyo3(get
|
|
25
|
+
#[pyo3(get)]
|
|
26
26
|
return_key: bool,
|
|
27
|
-
#[pyo3(get
|
|
27
|
+
#[pyo3(get)]
|
|
28
28
|
no_update_lru: bool,
|
|
29
|
-
#[pyo3(get
|
|
29
|
+
#[pyo3(get)]
|
|
30
30
|
mark_stale: bool,
|
|
31
|
-
#[pyo3(get
|
|
31
|
+
#[pyo3(get)]
|
|
32
32
|
cache_ttl: Option<u32>,
|
|
33
|
-
#[pyo3(get
|
|
33
|
+
#[pyo3(get)]
|
|
34
34
|
recache_ttl: Option<u32>,
|
|
35
|
-
#[pyo3(get
|
|
35
|
+
#[pyo3(get)]
|
|
36
36
|
vivify_on_miss_ttl: Option<u32>,
|
|
37
|
-
#[pyo3(get
|
|
37
|
+
#[pyo3(get)]
|
|
38
38
|
client_flag: Option<u32>,
|
|
39
|
-
#[pyo3(get
|
|
39
|
+
#[pyo3(get)]
|
|
40
40
|
ma_initial_value: Option<u64>,
|
|
41
|
-
#[pyo3(get
|
|
41
|
+
#[pyo3(get)]
|
|
42
42
|
ma_delta_value: Option<u64>,
|
|
43
|
-
#[pyo3(get
|
|
43
|
+
#[pyo3(get)]
|
|
44
44
|
cas_token: Option<u32>,
|
|
45
|
-
#[pyo3(get
|
|
45
|
+
#[pyo3(get)]
|
|
46
46
|
opaque: Option<Vec<u8>>,
|
|
47
|
-
#[pyo3(get
|
|
47
|
+
#[pyo3(get)]
|
|
48
48
|
mode: Option<u8>,
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -251,8 +251,86 @@ impl RequestFlags {
|
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
|
|
255
|
-
|
|
254
|
+
/// Return a copy of this object with the specified fields replaced.
|
|
255
|
+
///
|
|
256
|
+
/// Only keyword arguments that are explicitly provided (non-None) override the
|
|
257
|
+
/// corresponding field. Fields not mentioned keep their current value.
|
|
258
|
+
///
|
|
259
|
+
/// Note: passing `None` explicitly for an optional field (e.g. `cache_ttl=None`)
|
|
260
|
+
/// keeps the existing value rather than unsetting it. To unset an optional field,
|
|
261
|
+
/// construct a new `RequestFlags` directly.
|
|
262
|
+
#[allow(clippy::too_many_arguments)]
|
|
263
|
+
#[pyo3(
|
|
264
|
+
signature = (
|
|
265
|
+
/,
|
|
266
|
+
*,
|
|
267
|
+
no_reply=None,
|
|
268
|
+
return_client_flag=None,
|
|
269
|
+
return_cas_token=None,
|
|
270
|
+
return_value=None,
|
|
271
|
+
return_ttl=None,
|
|
272
|
+
return_size=None,
|
|
273
|
+
return_last_access=None,
|
|
274
|
+
return_fetched=None,
|
|
275
|
+
return_key=None,
|
|
276
|
+
no_update_lru=None,
|
|
277
|
+
mark_stale=None,
|
|
278
|
+
cache_ttl=None,
|
|
279
|
+
recache_ttl=None,
|
|
280
|
+
vivify_on_miss_ttl=None,
|
|
281
|
+
client_flag=None,
|
|
282
|
+
ma_initial_value=None,
|
|
283
|
+
ma_delta_value=None,
|
|
284
|
+
cas_token=None,
|
|
285
|
+
opaque=None,
|
|
286
|
+
mode=None
|
|
287
|
+
)
|
|
288
|
+
)]
|
|
289
|
+
pub fn replace(
|
|
290
|
+
&self,
|
|
291
|
+
no_reply: Option<bool>,
|
|
292
|
+
return_client_flag: Option<bool>,
|
|
293
|
+
return_cas_token: Option<bool>,
|
|
294
|
+
return_value: Option<bool>,
|
|
295
|
+
return_ttl: Option<bool>,
|
|
296
|
+
return_size: Option<bool>,
|
|
297
|
+
return_last_access: Option<bool>,
|
|
298
|
+
return_fetched: Option<bool>,
|
|
299
|
+
return_key: Option<bool>,
|
|
300
|
+
no_update_lru: Option<bool>,
|
|
301
|
+
mark_stale: Option<bool>,
|
|
302
|
+
cache_ttl: Option<u32>,
|
|
303
|
+
recache_ttl: Option<u32>,
|
|
304
|
+
vivify_on_miss_ttl: Option<u32>,
|
|
305
|
+
client_flag: Option<u32>,
|
|
306
|
+
ma_initial_value: Option<u64>,
|
|
307
|
+
ma_delta_value: Option<u64>,
|
|
308
|
+
cas_token: Option<u32>,
|
|
309
|
+
opaque: Option<Vec<u8>>,
|
|
310
|
+
mode: Option<u8>,
|
|
311
|
+
) -> Self {
|
|
312
|
+
RequestFlags {
|
|
313
|
+
no_reply: no_reply.unwrap_or(self.no_reply),
|
|
314
|
+
return_client_flag: return_client_flag.unwrap_or(self.return_client_flag),
|
|
315
|
+
return_cas_token: return_cas_token.unwrap_or(self.return_cas_token),
|
|
316
|
+
return_value: return_value.unwrap_or(self.return_value),
|
|
317
|
+
return_ttl: return_ttl.unwrap_or(self.return_ttl),
|
|
318
|
+
return_size: return_size.unwrap_or(self.return_size),
|
|
319
|
+
return_last_access: return_last_access.unwrap_or(self.return_last_access),
|
|
320
|
+
return_fetched: return_fetched.unwrap_or(self.return_fetched),
|
|
321
|
+
return_key: return_key.unwrap_or(self.return_key),
|
|
322
|
+
no_update_lru: no_update_lru.unwrap_or(self.no_update_lru),
|
|
323
|
+
mark_stale: mark_stale.unwrap_or(self.mark_stale),
|
|
324
|
+
cache_ttl: cache_ttl.or(self.cache_ttl),
|
|
325
|
+
recache_ttl: recache_ttl.or(self.recache_ttl),
|
|
326
|
+
vivify_on_miss_ttl: vivify_on_miss_ttl.or(self.vivify_on_miss_ttl),
|
|
327
|
+
client_flag: client_flag.or(self.client_flag),
|
|
328
|
+
ma_initial_value: ma_initial_value.or(self.ma_initial_value),
|
|
329
|
+
ma_delta_value: ma_delta_value.or(self.ma_delta_value),
|
|
330
|
+
cas_token: cas_token.or(self.cas_token),
|
|
331
|
+
opaque: opaque.or_else(|| self.opaque.clone()),
|
|
332
|
+
mode: mode.or(self.mode),
|
|
333
|
+
}
|
|
256
334
|
}
|
|
257
335
|
|
|
258
336
|
pub fn __str__(&self) -> String {
|
|
@@ -559,4 +559,171 @@ mod tests {
|
|
|
559
559
|
b" q f c v t s l h k u I T1 R2 N3 F4 J5 D6 C7 Oop ME"
|
|
560
560
|
);
|
|
561
561
|
}
|
|
562
|
+
|
|
563
|
+
// Helper: all-None replace call (no overrides)
|
|
564
|
+
fn replace_none(flags: &RequestFlags) -> RequestFlags {
|
|
565
|
+
flags.replace(
|
|
566
|
+
None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
|
567
|
+
None, None, None, None, None, None,
|
|
568
|
+
)
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
#[test]
|
|
572
|
+
fn test_replace_no_args_returns_equal() {
|
|
573
|
+
let base = RequestFlags::new(
|
|
574
|
+
true,
|
|
575
|
+
true,
|
|
576
|
+
false,
|
|
577
|
+
false,
|
|
578
|
+
false,
|
|
579
|
+
false,
|
|
580
|
+
false,
|
|
581
|
+
false,
|
|
582
|
+
false,
|
|
583
|
+
false,
|
|
584
|
+
false,
|
|
585
|
+
Some(300),
|
|
586
|
+
None,
|
|
587
|
+
None,
|
|
588
|
+
None,
|
|
589
|
+
None,
|
|
590
|
+
None,
|
|
591
|
+
None,
|
|
592
|
+
None,
|
|
593
|
+
None,
|
|
594
|
+
);
|
|
595
|
+
assert_eq!(replace_none(&base), base);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
#[test]
|
|
599
|
+
fn test_replace_bool_flag() {
|
|
600
|
+
let base = default_flags();
|
|
601
|
+
let updated = base.replace(
|
|
602
|
+
Some(true), // no_reply
|
|
603
|
+
None,
|
|
604
|
+
None,
|
|
605
|
+
None,
|
|
606
|
+
None,
|
|
607
|
+
None,
|
|
608
|
+
None,
|
|
609
|
+
None,
|
|
610
|
+
None,
|
|
611
|
+
None,
|
|
612
|
+
None,
|
|
613
|
+
None,
|
|
614
|
+
None,
|
|
615
|
+
None,
|
|
616
|
+
None,
|
|
617
|
+
None,
|
|
618
|
+
None,
|
|
619
|
+
None,
|
|
620
|
+
None,
|
|
621
|
+
None,
|
|
622
|
+
);
|
|
623
|
+
assert_eq!(push_to_vec(&updated), b" q");
|
|
624
|
+
// base is unchanged
|
|
625
|
+
assert_eq!(push_to_vec(&base), b"");
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
#[test]
|
|
629
|
+
fn test_replace_optional_field() {
|
|
630
|
+
let base = default_flags();
|
|
631
|
+
let updated = base.replace(
|
|
632
|
+
None,
|
|
633
|
+
None,
|
|
634
|
+
None,
|
|
635
|
+
None,
|
|
636
|
+
None,
|
|
637
|
+
None,
|
|
638
|
+
None,
|
|
639
|
+
None,
|
|
640
|
+
None,
|
|
641
|
+
None,
|
|
642
|
+
None,
|
|
643
|
+
Some(600), // cache_ttl
|
|
644
|
+
None,
|
|
645
|
+
None,
|
|
646
|
+
None,
|
|
647
|
+
None,
|
|
648
|
+
None,
|
|
649
|
+
None,
|
|
650
|
+
None,
|
|
651
|
+
None,
|
|
652
|
+
);
|
|
653
|
+
assert_eq!(push_to_vec(&updated), b" T600");
|
|
654
|
+
assert_eq!(push_to_vec(&base), b"");
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
#[test]
|
|
658
|
+
fn test_replace_none_keeps_existing_optional() {
|
|
659
|
+
// Passing None for an optional field keeps the existing value, not unsets it
|
|
660
|
+
let base = RequestFlags::new(
|
|
661
|
+
false, false, false, false, false, false, false, false, false, false, false,
|
|
662
|
+
Some(300), // cache_ttl set
|
|
663
|
+
None, None, None, None, None, None, None, None,
|
|
664
|
+
);
|
|
665
|
+
let updated = replace_none(&base);
|
|
666
|
+
assert_eq!(push_to_vec(&updated), b" T300");
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
#[test]
|
|
670
|
+
fn test_replace_multiple_fields() {
|
|
671
|
+
let base = RequestFlags::new(
|
|
672
|
+
false, true, false, true, false, false, false, false, false, false, false, Some(60),
|
|
673
|
+
None, None, None, None, None, None, None, None,
|
|
674
|
+
);
|
|
675
|
+
let updated = base.replace(
|
|
676
|
+
Some(true), // add no_reply
|
|
677
|
+
None, // keep return_client_flag=true
|
|
678
|
+
Some(true), // add return_cas_token
|
|
679
|
+
None, // keep return_value=true
|
|
680
|
+
None,
|
|
681
|
+
None,
|
|
682
|
+
None,
|
|
683
|
+
None,
|
|
684
|
+
None,
|
|
685
|
+
None,
|
|
686
|
+
None,
|
|
687
|
+
None, // keep cache_ttl=60
|
|
688
|
+
Some(120), // add recache_ttl
|
|
689
|
+
None,
|
|
690
|
+
None,
|
|
691
|
+
None,
|
|
692
|
+
None,
|
|
693
|
+
None,
|
|
694
|
+
None,
|
|
695
|
+
None,
|
|
696
|
+
);
|
|
697
|
+
assert_eq!(push_to_vec(&updated), b" q f c v T60 R120");
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
#[test]
|
|
701
|
+
fn test_replace_opaque() {
|
|
702
|
+
let base = default_flags();
|
|
703
|
+
let updated = base.replace(
|
|
704
|
+
None,
|
|
705
|
+
None,
|
|
706
|
+
None,
|
|
707
|
+
None,
|
|
708
|
+
None,
|
|
709
|
+
None,
|
|
710
|
+
None,
|
|
711
|
+
None,
|
|
712
|
+
None,
|
|
713
|
+
None,
|
|
714
|
+
None,
|
|
715
|
+
None,
|
|
716
|
+
None,
|
|
717
|
+
None,
|
|
718
|
+
None,
|
|
719
|
+
None,
|
|
720
|
+
None,
|
|
721
|
+
None,
|
|
722
|
+
Some(b"abc".to_vec()),
|
|
723
|
+
None,
|
|
724
|
+
);
|
|
725
|
+
assert_eq!(push_to_vec(&updated), b" Oabc");
|
|
726
|
+
// base is unchanged
|
|
727
|
+
assert_eq!(push_to_vec(&base), b"");
|
|
728
|
+
}
|
|
562
729
|
}
|
|
@@ -1011,3 +1011,52 @@ class TestVersionConstants:
|
|
|
1011
1011
|
"""ServerVersion IntEnum values match Rust constants."""
|
|
1012
1012
|
assert SERVER_VERSION_AWS_1_6_6 == 1
|
|
1013
1013
|
assert SERVER_VERSION_STABLE == 2
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
class TestRequestFlagsReplace:
|
|
1017
|
+
def test_replace_no_args_returns_equal(self):
|
|
1018
|
+
base = RequestFlags(return_value=True, cache_ttl=300)
|
|
1019
|
+
assert base.replace() == base
|
|
1020
|
+
|
|
1021
|
+
def test_replace_bool_flag(self):
|
|
1022
|
+
base = RequestFlags(return_value=True)
|
|
1023
|
+
updated = base.replace(return_cas_token=True)
|
|
1024
|
+
assert updated.return_value is True
|
|
1025
|
+
assert updated.return_cas_token is True
|
|
1026
|
+
# base is unchanged
|
|
1027
|
+
assert base.return_cas_token is False
|
|
1028
|
+
|
|
1029
|
+
def test_replace_optional_field(self):
|
|
1030
|
+
base = RequestFlags(return_value=True)
|
|
1031
|
+
updated = base.replace(cache_ttl=600)
|
|
1032
|
+
assert updated.cache_ttl == 600
|
|
1033
|
+
assert updated.return_value is True
|
|
1034
|
+
# base is unchanged
|
|
1035
|
+
assert base.cache_ttl is None
|
|
1036
|
+
|
|
1037
|
+
def test_replace_none_keeps_existing_optional(self):
|
|
1038
|
+
base = RequestFlags(cache_ttl=300)
|
|
1039
|
+
# explicitly passing None keeps the existing value, not unsets it
|
|
1040
|
+
updated = base.replace(cache_ttl=None)
|
|
1041
|
+
assert updated.cache_ttl == 300
|
|
1042
|
+
|
|
1043
|
+
def test_replace_multiple_fields(self):
|
|
1044
|
+
base = RequestFlags(return_client_flag=True, return_value=True, cache_ttl=60)
|
|
1045
|
+
updated = base.replace(no_reply=True, return_cas_token=True, recache_ttl=120)
|
|
1046
|
+
assert updated.no_reply is True
|
|
1047
|
+
assert updated.return_client_flag is True # preserved
|
|
1048
|
+
assert updated.return_cas_token is True
|
|
1049
|
+
assert updated.return_value is True # preserved
|
|
1050
|
+
assert updated.cache_ttl == 60 # preserved
|
|
1051
|
+
assert updated.recache_ttl == 120
|
|
1052
|
+
|
|
1053
|
+
def test_replace_opaque(self):
|
|
1054
|
+
base = RequestFlags(return_value=True)
|
|
1055
|
+
updated = base.replace(opaque=b"abc")
|
|
1056
|
+
assert updated.opaque == b"abc"
|
|
1057
|
+
assert base.opaque is None
|
|
1058
|
+
|
|
1059
|
+
def test_fields_are_readonly(self):
|
|
1060
|
+
flags = RequestFlags(return_value=True)
|
|
1061
|
+
with pytest.raises(AttributeError):
|
|
1062
|
+
flags.return_value = False # type: ignore[misc]
|
{meta_memcache_socket-0.2.0b2 → meta_memcache_socket-0.3.0}/.github/pull_request_template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|