Skip to content

Commit 0b1ac03

Browse files
Maksim Novikovifduyue
authored andcommitted
Allow to specify value returned by gets when not enough data is available
RESP3 has native boolean types, to be able to differentiate between insufficient data in buffer and actual False value add option to specify custom sentinel returned by gets when not enough data is available. CamelCase is used to conform to other arguments naming. Closes: #114
1 parent dd15f01 commit 0b1ac03

File tree

5 files changed

+26
-7
lines changed

5 files changed

+26
-7
lines changed

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,12 @@ Example:
4747
b'hello'
4848
```
4949

50-
When the buffer does not contain a full reply, `gets` returns `False`. This
51-
means extra data is needed and `feed` should be called again before calling
52-
`gets` again:
50+
When the buffer does not contain a full reply, `gets` returns `False`.
51+
This means extra data is needed and `feed` should be called again before calling
52+
`gets` again. Alternatively you could provide custom sentinel object via parameter,
53+
which is useful for RESP3 protocol where native boolean types are supported:
54+
55+
Example:
5356

5457
```python
5558
>>> reader.feed("*2\r\n$5\r\nhello\r\n")
@@ -58,6 +61,9 @@ False
5861
>>> reader.feed("$5\r\nworld\r\n")
5962
>>> reader.gets()
6063
[b'hello', b'world']
64+
>>> reader = hiredis.Reader(notEnoughData=Ellipsis)
65+
>>> reader.gets()
66+
Ellipsis
6167
```
6268

6369
#### Unicode

hiredis/hiredis.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class Reader:
1111
replyError: Callable[[str], Exception] = ...,
1212
encoding: Optional[str] = ...,
1313
errors: Optional[str] = ...,
14+
notEnoughData: Any = ...,
1415
) -> None: ...
1516
def feed(
1617
self, __buf: Union[str, bytes], __off: int = ..., __len: int = ...

src/reader.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ static void Reader_dealloc(hiredis_ReaderObject *self) {
214214
redisReaderFree(self->reader);
215215
Py_XDECREF(self->protocolErrorClass);
216216
Py_XDECREF(self->replyErrorClass);
217+
Py_XDECREF(self->notEnoughDataObject);
217218

218219
((PyObject *)self)->ob_type->tp_free((PyObject*)self);
219220
}
@@ -268,14 +269,15 @@ static int _Reader_set_encoding(hiredis_ReaderObject *self, char *encoding, char
268269
}
269270

270271
static int Reader_init(hiredis_ReaderObject *self, PyObject *args, PyObject *kwds) {
271-
static char *kwlist[] = { "protocolError", "replyError", "encoding", "errors", NULL };
272+
static char *kwlist[] = { "protocolError", "replyError", "encoding", "errors", "notEnoughData", NULL };
272273
PyObject *protocolErrorClass = NULL;
273274
PyObject *replyErrorClass = NULL;
275+
PyObject *notEnoughData = NULL;
274276
char *encoding = NULL;
275277
char *errors = NULL;
276278

277-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOzz", kwlist,
278-
&protocolErrorClass, &replyErrorClass, &encoding, &errors))
279+
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOzzO", kwlist,
280+
&protocolErrorClass, &replyErrorClass, &encoding, &errors, &notEnoughData))
279281
return -1;
280282

281283
if (protocolErrorClass)
@@ -286,6 +288,9 @@ static int Reader_init(hiredis_ReaderObject *self, PyObject *args, PyObject *kwd
286288
if (!_Reader_set_exception(&self->replyErrorClass, replyErrorClass))
287289
return -1;
288290

291+
if (notEnoughData)
292+
self->notEnoughDataObject = notEnoughData;
293+
289294
return _Reader_set_encoding(self, encoding, errors);
290295
}
291296

@@ -299,11 +304,13 @@ static PyObject *Reader_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
299304

300305
self->encoding = NULL;
301306
self->errors = "strict"; // default to "strict" to mimic Python
307+
self->notEnoughDataObject = Py_False;
302308
self->shouldDecode = 1;
303309
self->protocolErrorClass = HIREDIS_STATE->HiErr_ProtocolError;
304310
self->replyErrorClass = HIREDIS_STATE->HiErr_ReplyError;
305311
Py_INCREF(self->protocolErrorClass);
306312
Py_INCREF(self->replyErrorClass);
313+
Py_INCREF(self->notEnoughDataObject);
307314

308315
self->error.ptype = NULL;
309316
self->error.pvalue = NULL;
@@ -368,7 +375,7 @@ static PyObject *Reader_gets(hiredis_ReaderObject *self, PyObject *args) {
368375
}
369376

370377
if (obj == NULL) {
371-
Py_RETURN_FALSE;
378+
return self->notEnoughDataObject;
372379
} else {
373380
/* Restore error when there is one. */
374381
if (self->error.ptype != NULL) {

src/reader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ typedef struct {
1111
int shouldDecode;
1212
PyObject *protocolErrorClass;
1313
PyObject *replyErrorClass;
14+
PyObject *notEnoughDataObject;
1415

1516
/* Stores error object in between incomplete calls to #gets, in order to
1617
* only set the error once a full reply has been read. Otherwise, the

test/reader.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,3 +314,7 @@ def test_reader_has_data(self):
314314
self.assertEquals(True, self.reader.has_data())
315315
self.reply()
316316
self.assertEquals(False, self.reader.has_data())
317+
318+
def test_custom_not_enough_data(self):
319+
self.reader = hiredis.Reader(notEnoughData=Ellipsis)
320+
assert self.reader.gets() is Ellipsis

0 commit comments

Comments
 (0)