Created
November 10, 2011 22:09
-
-
Save skrat/1356405 to your computer and use it in GitHub Desktop.
py3k patch pylibmc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/_pylibmcmodule.c b/_pylibmcmodule.c | |
index 7704682..e2da236 100644 | |
--- a/_pylibmcmodule.c | |
+++ b/_pylibmcmodule.c | |
@@ -46,6 +46,26 @@ | |
{ Py_INCREF(obj); \ | |
PyModule_AddObject(mod, nam, obj); } | |
+size_t | |
+strnlen(const char *s, size_t maxlen) | |
+{ | |
+ const char * eospos; | |
+ eospos = memchr(s, (int)'\0', maxlen); | |
+ return (eospos == NULL ? maxlen : (size_t)(eospos-s)); | |
+} | |
+ | |
+char * | |
+strndup (char const *s, size_t n) | |
+{ | |
+ size_t len = strnlen (s, n); | |
+ char *new = malloc (len + 1); | |
+ | |
+ if (new == NULL) | |
+ return NULL; | |
+ | |
+ new[len] = '\0'; | |
+ return memcpy (new, s, len); | |
+} | |
/* {{{ Type methods */ | |
static PylibMC_Client *PylibMC_ClientType_new(PyTypeObject *type, | |
@@ -74,7 +94,7 @@ static void PylibMC_ClientType_dealloc(PylibMC_Client *self) { | |
memcached_free(self->mc); | |
} | |
- self->ob_type->tp_free(self); | |
+ Py_TYPE(self)->tp_free(self); | |
} | |
/* }}} */ | |
@@ -136,10 +156,10 @@ static int PylibMC_Client_init(PylibMC_Client *self, PyObject *args, | |
got_server |= 1; | |
port = 0; | |
- if (PyString_Check(c_srv)) { | |
+ if (PyBytes_Check(c_srv)) { | |
memcached_server_st *list; | |
- list = memcached_servers_parse(PyString_AS_STRING(c_srv)); | |
+ list = memcached_servers_parse(PyBytes_AsString(c_srv)); | |
if (list == NULL) { | |
PyErr_SetString(PylibMCExc_MemcachedError, | |
"memcached_servers_parse returned NULL"); | |
@@ -287,11 +307,11 @@ static PyObject *_PylibMC_Inflate(char *value, size_t size) { | |
/* Output buffer */ | |
rvalsz = ZLIB_BUFSZ; | |
- out_obj = PyString_FromStringAndSize(NULL, rvalsz); | |
+ out_obj = PyBytes_FromStringAndSize(NULL, rvalsz); | |
if (out_obj == NULL) { | |
return NULL; | |
} | |
- out = PyString_AS_STRING(out_obj); | |
+ out = PyBytes_AsString(out_obj); | |
/* TODO 64-bit fix size/rvalsz */ | |
assert(size < 0xffffffffU); | |
@@ -330,12 +350,12 @@ static PyObject *_PylibMC_Inflate(char *value, size_t size) { | |
} | |
/* Fall-through */ | |
case Z_OK: | |
- if (_PyString_Resize(&out_obj, (Py_ssize_t)(rvalsz << 1)) < 0) { | |
+ if (_PyBytes_Resize(&out_obj, (Py_ssize_t)(rvalsz << 1)) < 0) { | |
inflateEnd(&strm); | |
goto error; | |
} | |
/* Wind forward */ | |
- out = PyString_AS_STRING(out_obj); | |
+ out = PyBytes_AsString(out_obj); | |
strm.next_out = (Byte *)(out + rvalsz); | |
strm.avail_out = (uInt)rvalsz; | |
rvalsz = rvalsz << 1; | |
@@ -351,7 +371,7 @@ static PyObject *_PylibMC_Inflate(char *value, size_t size) { | |
goto error; | |
} | |
- _PyString_Resize(&out_obj, strm.total_out); | |
+ _PyBytes_Resize(&out_obj, strm.total_out); | |
return out_obj; | |
error: | |
Py_DECREF(out_obj); | |
@@ -374,8 +394,8 @@ static PyObject *_PylibMC_parse_memcached_value(char *value, size_t size, | |
if ((inflated = _PylibMC_Inflate(value, size)) == NULL) { | |
return NULL; | |
} | |
- value = PyString_AS_STRING(inflated); | |
- size = PyString_GET_SIZE(inflated); | |
+ value = PyBytes_AsString(inflated); | |
+ size = PyBytes_GET_SIZE(inflated); | |
} | |
#else | |
if (flags & PYLIBMC_FLAG_ZLIB) { | |
@@ -392,22 +412,22 @@ static PyObject *_PylibMC_parse_memcached_value(char *value, size_t size, | |
case PYLIBMC_FLAG_INTEGER: | |
case PYLIBMC_FLAG_LONG: | |
case PYLIBMC_FLAG_BOOL: | |
- /* PyInt_FromString doesn't take a length param and we're | |
+ /* PyLong_FromString doesn't take a length param and we're | |
not NULL-terminated, so we'll have to make an | |
intermediate Python string out of it */ | |
- tmp = PyString_FromStringAndSize(value, size); | |
+ tmp = PyBytes_FromStringAndSize(value, size); | |
if(tmp == NULL) { | |
goto cleanup; | |
} | |
- retval = PyInt_FromString(PyString_AS_STRING(tmp), NULL, 10); | |
+ retval = PyLong_FromString(PyBytes_AsString(tmp), NULL, 10); | |
if(retval != NULL && dtype == PYLIBMC_FLAG_BOOL) { | |
Py_DECREF(tmp); | |
tmp = retval; | |
- retval = PyBool_FromLong(PyInt_AS_LONG(tmp)); | |
+ retval = PyBool_FromLong(PyLong_AS_LONG(tmp)); | |
} | |
break; | |
case PYLIBMC_FLAG_NONE: | |
- retval = PyString_FromStringAndSize(value, (Py_ssize_t)size); | |
+ retval = PyBytes_FromStringAndSize(value, (Py_ssize_t)size); | |
break; | |
default: | |
PyErr_Format(PylibMCExc_MemcachedError, | |
@@ -446,7 +466,7 @@ static PyObject *PylibMC_Client_get(PylibMC_Client *self, PyObject *arg) { | |
Py_BEGIN_ALLOW_THREADS; | |
mc_val = memcached_get(self->mc, | |
- PyString_AS_STRING(arg), PyString_GET_SIZE(arg), | |
+ PyBytes_AsString(arg), PyBytes_GET_SIZE(arg), | |
&val_size, &flags, &error); | |
Py_END_ALLOW_THREADS; | |
@@ -456,7 +476,7 @@ static PyObject *PylibMC_Client_get(PylibMC_Client *self, PyObject *arg) { | |
return r; | |
} else if (error == MEMCACHED_SUCCESS) { | |
/* This happens for empty values, and so we fake an empty string. */ | |
- return PyString_FromStringAndSize("", 0); | |
+ return PyBytes_FromStringAndSize("", 0); | |
} else if (error == MEMCACHED_NOTFOUND) { | |
/* Since python-memcache returns None when the key doesn't exist, | |
* so shall we. */ | |
@@ -464,8 +484,8 @@ static PyObject *PylibMC_Client_get(PylibMC_Client *self, PyObject *arg) { | |
} | |
return PylibMC_ErrFromMemcachedWithKey(self, "memcached_get", error, | |
- PyString_AS_STRING(arg), | |
- PyString_GET_SIZE(arg)); | |
+ PyBytes_AsString(arg), | |
+ PyBytes_GET_SIZE(arg)); | |
} | |
static PyObject *PylibMC_Client_gets(PylibMC_Client *self, PyObject *arg) { | |
@@ -488,8 +508,8 @@ static PyObject *PylibMC_Client_gets(PylibMC_Client *self, PyObject *arg) { | |
/* Use an mget to fetch the key. | |
* mget is the only function that returns a memcached_result_st, | |
* which is the only way to get at the returned cas value. */ | |
- *keys = PyString_AS_STRING(arg); | |
- *keylengths = (size_t)PyString_GET_SIZE(arg); | |
+ *keys = PyBytes_AsString(arg); | |
+ *keylengths = (size_t)PyBytes_GET_SIZE(arg); | |
Py_BEGIN_ALLOW_THREADS; | |
@@ -758,7 +778,7 @@ static int _PylibMC_SerializeValue(PyObject* key_obj, | |
serialized->flags = PYLIBMC_FLAG_NONE; | |
if(!_PylibMC_CheckKey(key_obj) | |
- || PyString_AsStringAndSize(key_obj, &serialized->key, | |
+ || PyBytes_AsStringAndSize(key_obj, &serialized->key, | |
&serialized->key_len) == -1) { | |
return false; | |
} | |
@@ -776,7 +796,7 @@ static int _PylibMC_SerializeValue(PyObject* key_obj, | |
} | |
/* Ignore empty prefixes */ | |
- if (!PyString_Size(key_prefix)) { | |
+ if (!PyBytes_Size(key_prefix)) { | |
key_prefix = NULL; | |
} | |
} | |
@@ -785,9 +805,9 @@ static int _PylibMC_SerializeValue(PyObject* key_obj, | |
if (key_prefix != NULL) { | |
PyObject* prefixed_key_obj = NULL; /* freed by _PylibMC_FreeMset */ | |
- prefixed_key_obj = PyString_FromFormat("%s%s", | |
- PyString_AS_STRING(key_prefix), | |
- PyString_AS_STRING(key_obj)); | |
+ prefixed_key_obj = PyBytes_FromFormat("%s%s", | |
+ PyBytes_AsString(key_prefix), | |
+ PyBytes_AsString(key_obj)); | |
if(prefixed_key_obj == NULL) { | |
return false; | |
@@ -795,7 +815,7 @@ static int _PylibMC_SerializeValue(PyObject* key_obj, | |
/* check the key and overwrite the C string */ | |
if(!_PylibMC_CheckKey(prefixed_key_obj) | |
- || PyString_AsStringAndSize(prefixed_key_obj, | |
+ || PyBytes_AsStringAndSize(prefixed_key_obj, | |
&serialized->key, | |
&serialized->key_len) == -1) { | |
Py_DECREF(prefixed_key_obj); | |
@@ -811,18 +831,18 @@ static int _PylibMC_SerializeValue(PyObject* key_obj, | |
/* First build store_val, a Python String object, out of the object | |
we were passed */ | |
- if (PyString_Check(value_obj)) { | |
+ if (PyBytes_Check(value_obj)) { | |
store_val = value_obj; | |
Py_INCREF(store_val); /* because we'll be decring it again in | |
pylibmc_mset_free*/ | |
} else if (PyBool_Check(value_obj)) { | |
serialized->flags |= PYLIBMC_FLAG_BOOL; | |
- PyObject* tmp = PyNumber_Int(value_obj); | |
+ PyObject* tmp = PyNumber_Long(value_obj); | |
store_val = PyObject_Str(tmp); | |
Py_DECREF(tmp); | |
- } else if (PyInt_Check(value_obj)) { | |
+ } else if (PyLong_Check(value_obj)) { | |
serialized->flags |= PYLIBMC_FLAG_INTEGER; | |
- PyObject* tmp = PyNumber_Int(value_obj); | |
+ PyObject* tmp = PyNumber_Long(value_obj); | |
store_val = PyObject_Str(tmp); | |
Py_DECREF(tmp); | |
} else if (PyLong_Check(value_obj)) { | |
@@ -842,7 +862,7 @@ static int _PylibMC_SerializeValue(PyObject* key_obj, | |
return false; | |
} | |
- if (PyString_AsStringAndSize(store_val, &serialized->value, | |
+ if (PyBytes_AsStringAndSize(store_val, &serialized->value, | |
&serialized->value_len) == -1) { | |
if (serialized->flags == PYLIBMC_FLAG_NONE) { | |
/* For some reason we weren't able to extract the value/size | |
@@ -1078,7 +1098,7 @@ static PyObject *_PylibMC_IncrMulti(PylibMC_Client *self, | |
if(nkeys == -1) | |
return NULL; | |
- if(key_prefix == NULL || PyString_Size(key_prefix) < 1) { | |
+ if(key_prefix == NULL || PyBytes_Size(key_prefix) < 1) { | |
/* if it's 0-length, we can safely pretend it doesn't exist */ | |
key_prefix = NULL; | |
} | |
@@ -1120,9 +1140,9 @@ static PyObject *_PylibMC_IncrMulti(PylibMC_Client *self, | |
if(key_prefix != NULL) { | |
PyObject* newkey = NULL; | |
- newkey = PyString_FromFormat("%s%s", | |
- PyString_AS_STRING(key_prefix), | |
- PyString_AS_STRING(key)); | |
+ newkey = PyBytes_FromFormat("%s%s", | |
+ PyBytes_AsString(key_prefix), | |
+ PyBytes_AsString(key)); | |
if(!_PylibMC_CheckKey(newkey)) { | |
Py_XDECREF(newkey); | |
@@ -1145,7 +1165,7 @@ static PyObject *_PylibMC_IncrMulti(PylibMC_Client *self, | |
key = newkey; | |
} | |
- if(PyString_AsStringAndSize(key, &incrs[idx].key, | |
+ if(PyBytes_AsStringAndSize(key, &incrs[idx].key, | |
&incrs[idx].key_len) == -1) | |
goto loopcleanup; | |
@@ -1351,7 +1371,7 @@ static PyObject *PylibMC_Client_get_multi( | |
goto earlybird; | |
} | |
- PyString_AsStringAndSize(ckey, &key, &key_len); | |
+ PyBytes_AsStringAndSize(ckey, &key, &key_len); | |
key_lens[i] = (size_t)(key_len + prefix_len); | |
@@ -1361,19 +1381,19 @@ static PyObject *PylibMC_Client_get_multi( | |
/* determine rkey, the prefixed ckey */ | |
if (prefix != NULL) { | |
- rkey = PyString_FromStringAndSize(prefix, prefix_len); | |
- PyString_Concat(&rkey, ckey); | |
+ rkey = PyBytes_FromStringAndSize(prefix, prefix_len); | |
+ PyBytes_Concat(&rkey, ckey); | |
if (rkey == NULL) | |
goto earlybird; | |
- rkey = PyString_FromFormat("%s%s", | |
- prefix, PyString_AS_STRING(ckey)); | |
+ rkey = PyBytes_FromFormat("%s%s", | |
+ prefix, PyBytes_AsString(ckey)); | |
} else { | |
Py_INCREF(ckey); | |
rkey = ckey; | |
} | |
Py_DECREF(ckey); | |
- keys[i] = PyString_AS_STRING(rkey); | |
+ keys[i] = PyBytes_AsString(rkey); | |
key_objs[i++] = rkey; | |
} | |
nkeys = i; | |
@@ -1416,7 +1436,7 @@ static PyObject *PylibMC_Client_get_multi( | |
/* Explicitly construct a key string object so that NUL-bytes and the | |
* likes can be contained within the keys (this is possible in the | |
* binary protocol.) */ | |
- key_obj = PyString_FromStringAndSize(memcached_result_key_value(res) + prefix_len, | |
+ key_obj = PyBytes_FromStringAndSize(memcached_result_key_value(res) + prefix_len, | |
memcached_result_key_length(res) - prefix_len); | |
if (key_obj == NULL) | |
goto unpack_error; | |
@@ -1501,7 +1521,7 @@ static PyObject *_PylibMC_DoMulti(PyObject *values, PyObject *func, | |
/* Calculate args. */ | |
if (is_mapping) { | |
PyObject *value; | |
- char *key_str = PyString_AS_STRING(item); | |
+ char *key_str = PyBytes_AsString(item); | |
if ((value = PyMapping_GetItemString(values, key_str)) == NULL) | |
goto iter_error; | |
@@ -1642,7 +1662,7 @@ static PyObject *PylibMC_Client_get_behaviors(PylibMC_Client *self) { | |
PyObject *x; | |
bval = memcached_behavior_get(self->mc, b->flag); | |
- x = PyInt_FromLong((long)bval); | |
+ x = PyLong_FromLong((long)bval); | |
if (x == NULL || PyDict_SetItemString(retval, b->name, x) == -1) { | |
Py_XDECREF(x); | |
goto error; | |
@@ -1670,12 +1690,12 @@ static PyObject *PylibMC_Client_set_behaviors(PylibMC_Client *self, | |
continue; | |
} else if ((py_v = PyMapping_GetItemString(behaviors, b->name)) == NULL) { | |
goto error; | |
- } else if (!PyInt_Check(py_v)) { | |
+ } else if (!PyLong_Check(py_v)) { | |
PyErr_Format(PyExc_TypeError, "behavior %.32s must be int", b->name); | |
goto error; | |
} | |
- v = (uint64_t)PyInt_AS_LONG(py_v); | |
+ v = (uint64_t)PyLong_AS_LONG(py_v); | |
Py_DECREF(py_v); | |
r = memcached_behavior_set(self->mc, b->flag, v); | |
@@ -1724,7 +1744,7 @@ _PylibMC_AddServerCallback(memcached_st *mc, | |
goto error; | |
} | |
- curr_value = PyString_FromString(mc_val); | |
+ curr_value = PyBytes_FromString(mc_val); | |
free(mc_val); | |
if (curr_value == NULL) | |
goto error; | |
@@ -1737,7 +1757,7 @@ _PylibMC_AddServerCallback(memcached_st *mc, | |
free(stat_keys); | |
- desc = PyString_FromFormat("%s:%d (%u)", | |
+ desc = PyBytes_FromFormat("%s:%d (%u)", | |
server->hostname, server->port, | |
(unsigned int)context->index); | |
@@ -1828,11 +1848,11 @@ static PyObject *PylibMC_Client_flush_all(PylibMC_Client *self, | |
static char *kws[] = { "time", NULL }; | |
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!:flush_all", kws, | |
- &PyInt_Type, &time)) | |
+ &time)) | |
return NULL; | |
if (time != NULL) | |
- expire = PyInt_AS_LONG(time); | |
+ expire = PyLong_AS_LONG(time); | |
expire = (expire > 0) ? expire : 0; | |
@@ -1857,7 +1877,7 @@ static PyObject *PylibMC_Client_clone(PylibMC_Client *self) { | |
* cloned memcached_st for mc. */ | |
PylibMC_Client *clone; | |
- clone = (PylibMC_Client *)PyType_GenericNew(self->ob_type, NULL, NULL); | |
+ clone = (PylibMC_Client *)PyType_GenericNew(Py_TYPE(self), NULL, NULL); | |
if (clone == NULL) { | |
return NULL; | |
} | |
@@ -1987,13 +2007,13 @@ static int _PylibMC_CheckKey(PyObject *key) { | |
if (key == NULL) { | |
PyErr_SetString(PyExc_ValueError, "key must be given"); | |
return 0; | |
- } else if (!PyString_Check(key)) { | |
+ } else if (!PyBytes_Check(key)) { | |
PyErr_SetString(PyExc_TypeError, "key must be an instance of str"); | |
return 0; | |
} | |
return _PylibMC_CheckKeyStringAndSize( | |
- PyString_AS_STRING(key), PyString_GET_SIZE(key)); | |
+ PyBytes_AsString(key), PyBytes_GET_SIZE(key)); | |
} | |
static int _PylibMC_CheckKeyStringAndSize(char *key, Py_ssize_t size) { | |
@@ -2087,7 +2107,7 @@ static void _make_excs(PyObject *module) { | |
char excnam[64]; | |
snprintf(excnam, 64, "_pylibmc.%s", err->name); | |
err->exc = PyErr_NewException(excnam, PylibMCExc_MemcachedError, NULL); | |
- PyObject_SetAttrString(err->exc, "retcode", PyInt_FromLong(err->rc)); | |
+ PyObject_SetAttrString(err->exc, "retcode", PyLong_FromLong(err->rc)); | |
PyModule_AddObject(module, err->name, (PyObject *)err->exc); | |
PyList_Append(exc_objs, | |
Py_BuildValue("sO", err->name, (PyObject *)err->exc)); | |
@@ -2117,7 +2137,7 @@ static void _make_behavior_consts(PyObject *mod) { | |
behavior_names = PyList_New(0); | |
for (b = PylibMC_behaviors; b->name != NULL; b++) { | |
- PyList_Append(behavior_names, PyString_FromString(b->name)); | |
+ PyList_Append(behavior_names, PyBytes_FromString(b->name)); | |
} | |
PyModule_AddObject(mod, "all_behaviors", behavior_names); | |
@@ -2127,7 +2147,64 @@ static PyMethodDef PylibMC_functions[] = { | |
{NULL, NULL, 0, NULL} | |
}; | |
-PyMODINIT_FUNC init_pylibmc(void) { | |
+struct module_state { | |
+ PyObject *error; | |
+}; | |
+ | |
+#if PY_MAJOR_VERSION >= 3 | |
+#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) | |
+#else | |
+#define GETSTATE(m) (&_state) | |
+static struct module_state _state; | |
+#endif | |
+ | |
+static PyObject * | |
+error_out(PyObject *m) { | |
+ struct module_state *st = GETSTATE(m); | |
+ PyErr_SetString(st->error, "something bad happened"); | |
+ return NULL; | |
+} | |
+ | |
+static PyMethodDef myextension_methods[] = { | |
+ {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL}, | |
+ {NULL, NULL} | |
+}; | |
+ | |
+#if PY_MAJOR_VERSION >= 3 | |
+ | |
+static int pylibmc_traverse(PyObject *m, visitproc visit, void *arg) { | |
+ Py_VISIT(GETSTATE(m)->error); | |
+ return 0; | |
+} | |
+ | |
+static int pylibmc_clear(PyObject *m) { | |
+ Py_CLEAR(GETSTATE(m)->error); | |
+ return 0; | |
+} | |
+ | |
+static struct PyModuleDef moduledef = { | |
+ PyModuleDef_HEAD_INIT, | |
+ "_pylibmc", | |
+ NULL, | |
+ sizeof(struct module_state), | |
+ PylibMC_functions, | |
+ NULL, | |
+ pylibmc_traverse, | |
+ pylibmc_clear, | |
+ NULL | |
+}; | |
+ | |
+#define INITERROR return NULL | |
+ | |
+PyObject * PyInit_pylibmc(void) | |
+ | |
+#else | |
+#define INITERROR return | |
+ | |
+void init_pylibmc(void) | |
+#endif | |
+{ | |
+ | |
PyObject *module; | |
if (!_check_libmemcached_version()) | |
@@ -2140,7 +2217,10 @@ PyMODINIT_FUNC init_pylibmc(void) { | |
return; | |
} | |
- module = Py_InitModule3("_pylibmc", PylibMC_functions, | |
+#if PY_MAJOR_VERSION >= 3 | |
+ module = PyModule_Create(&moduledef); | |
+#else | |
+ module = Py_InitModule("_pylibmc", PylibMC_functions, | |
"Hand-made wrapper for libmemcached.\n\ | |
\n\ | |
You should really use the Python wrapper around this library.\n\ | |
@@ -2155,6 +2235,8 @@ no port should be given. libmemcached can parse strings as well::\n\ | |
See libmemcached's memcached_servers_parse for more info on that. I'm told \n\ | |
you can use UNIX domain sockets by specifying paths, and multiple servers \n\ | |
by using comma-separation. Good luck with that.\n"); | |
+#endif | |
+ | |
if (module == NULL) { | |
return; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Were you able to compile pylibmc finally with python 3? Or what error do you get?