Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump hiredis from 0.13.3 to 1.0.0 #104

Merged
merged 1 commit into from
Mar 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def version():

ext = Extension("hiredis.hiredis",
sources=sorted(glob.glob("src/*.c") +
["vendor/hiredis/%s.c" % src for src in ("read", "sds")]),
["vendor/hiredis/%s.c" % src for src in ("alloc", "read", "sds")]),
include_dirs=["vendor"])

setup(
Expand Down
64 changes: 55 additions & 9 deletions src/reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,26 @@ static void *tryParentize(const redisReadTask *task, PyObject *obj) {
PyObject *parent;
if (task && task->parent) {
parent = (PyObject*)task->parent->obj;
assert(PyList_CheckExact(parent));
PyList_SET_ITEM(parent, task->idx, obj);
switch (task->parent->type) {
case REDIS_REPLY_MAP:
if (task->idx % 2 == 0) {
/* Set a temporary item to save the object as a key. */
PyDict_SetItem(parent, obj, Py_None);
} else {
/* Pop the temporary item and set proper key and value. */
PyObject *last_item = PyObject_CallMethod(parent, "popitem", NULL);
PyObject *last_key = PyTuple_GetItem(last_item, 0);
PyDict_SetItem(parent, last_key, obj);
}
break;
case REDIS_REPLY_SET:
assert(PyAnySet_CheckExact(parent));
PySet_Add(parent, obj);
break;
default:
assert(PyList_CheckExact(parent));
PyList_SET_ITEM(parent, task->idx, obj);
}
}
return obj;
}
Expand Down Expand Up @@ -127,14 +145,28 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
Py_INCREF(obj);
}
} else {
if (task->type == REDIS_REPLY_VERB) {
/* Skip 4 bytes of verbatim type header. */
memmove(str, str+4, len);
len -= 4;
}
obj = createDecodedString(self, str, len);
}
return tryParentize(task, obj);
}

static void *createArrayObject(const redisReadTask *task, int elements) {
static void *createArrayObject(const redisReadTask *task, size_t elements) {
PyObject *obj;
obj = PyList_New(elements);
switch (task->type) {
case REDIS_REPLY_MAP:
obj = PyDict_New();
break;
case REDIS_REPLY_SET:
obj = PySet_New(NULL);
break;
default:
obj = PyList_New(elements);
}
return tryParentize(task, obj);
}

Expand All @@ -144,28 +176,42 @@ static void *createIntegerObject(const redisReadTask *task, long long value) {
return tryParentize(task, obj);
}

static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t le) {
PyObject *obj;
obj = PyFloat_FromDouble(value);
return tryParentize(task, obj);
}

static void *createNilObject(const redisReadTask *task) {
PyObject *obj = Py_None;
Py_INCREF(obj);
return tryParentize(task, obj);
}

static void *createBoolObject(const redisReadTask *task, int bval) {
PyObject *obj;
obj = PyBool_FromLong((long)bval);
return tryParentize(task, obj);
}

static void freeObject(void *obj) {
Py_XDECREF(obj);
}

redisReplyObjectFunctions hiredis_ObjectFunctions = {
createStringObject, // void *(*createString)(const redisReadTask*, char*, size_t);
createArrayObject, // void *(*createArray)(const redisReadTask*, int);
createArrayObject, // void *(*createArray)(const redisReadTask*, size_t);
createIntegerObject, // void *(*createInteger)(const redisReadTask*, long long);
createDoubleObject, // void *(*createDoubleObject)(const redisReadTask*, double, char*, size_t);
createNilObject, // void *(*createNil)(const redisReadTask*);
createBoolObject, // void *(*createBoolObject)(const redisReadTask*, int);
freeObject // void (*freeObject)(void*);
};

static void Reader_dealloc(hiredis_ReaderObject *self) {
// we don't need to free self->encoding as the buffer is managed by Python
// https://docs.python.org/3/c-api/arg.html#strings-and-buffers
redisReplyReaderFree(self->reader);
redisReaderFree(self->reader);
Py_XDECREF(self->protocolErrorClass);
Py_XDECREF(self->replyErrorClass);

Expand Down Expand Up @@ -289,7 +335,7 @@ static PyObject *Reader_feed(hiredis_ReaderObject *self, PyObject *args) {
goto error;
}

redisReplyReaderFeed(self->reader, (char *)buf.buf + off, len);
redisReaderFeed(self->reader, (char *)buf.buf + off, len);
PyBuffer_Release(&buf);
Py_RETURN_NONE;

Expand All @@ -308,8 +354,8 @@ static PyObject *Reader_gets(hiredis_ReaderObject *self, PyObject *args) {
return NULL;
}

if (redisReplyReaderGetReply(self->reader, (void**)&obj) == REDIS_ERR) {
errstr = redisReplyReaderGetError(self->reader);
if (redisReaderGetReply(self->reader, (void**)&obj) == REDIS_ERR) {
errstr = redisReaderGetError(self->reader);
/* protocolErrorClass might be a callable. call it, then use it's type */
err = createError(self->protocolErrorClass, errstr, strlen(errstr));
if (err != NULL) {
Expand Down
36 changes: 36 additions & 0 deletions test/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,42 @@ def test_integer(self):
self.reader.feed((":%d\r\n" % value).encode("ascii"))
self.assertEquals(value, self.reply())

def test_float(self):
value = -99.99
self.reader.feed(b",%f\r\n" % value)
self.assertEqual(value, self.reply())

def test_boolean_true(self):
self.reader.feed(b"#t\r\n")
self.assertTrue(self.reply())

def test_boolean_false(self):
self.reader.feed(b"#f\r\n")
self.assertFalse(False, self.reply())

def test_none(self):
self.reader.feed(b"_\r\n")
self.assertIsNone(self.reply())

def test_set(self):
self.reader.feed(b"~3\r\n+tangerine\r\n_\r\n,10.5\r\n")
self.assertEqual({b"tangerine", None, 10.5}, self.reply())

def test_dict(self):
self.reader.feed(b"%2\r\n+radius\r\n,4.5\r\n+diameter\r\n:9\r\n")
self.assertEqual({b"radius": 4.5, b"diameter": 9}, self.reply())

def test_vector(self):
self.reader.feed(b">4\r\n+pubsub\r\n+message\r\n+channel\r\n+message\r\n")
self.assertEqual(
[b"pubsub", b"message", b"channel", b"message"], self.reply()
)

def test_verbatim_string(self):
value = b"text"
self.reader.feed(b"=8\r\ntxt:%s\r\n" % value)
self.assertEqual(value, self.reply())

def test_status_string(self):
self.reader.feed(b"+ok\r\n")
self.assertEquals(b"ok", self.reply())
Expand Down