[Python-modules-commits] [pylibmc] 11/18: Import pylibmc_1.5.2.orig.tar.gz

Michael Fladischer fladi at moszumanska.debian.org
Mon Jul 24 13:23:57 UTC 2017


This is an automated email from the git hooks/post-receive script.

fladi pushed a commit to branch master
in repository pylibmc.

commit 01fa087f70b0369acfe51309e5579c75072f0964
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date:   Mon Jul 24 13:40:11 2017 +0200

    Import pylibmc_1.5.2.orig.tar.gz
---
 MANIFEST.in                 |   2 +-
 PKG-INFO                    |   3 +-
 docs/failover.svg           | 130 +++++++++++++++++++++++++++++++++++++
 docs/install.rst            |   2 +-
 docs/reference.rst          |  18 ++----
 setup.py                    |   1 +
 src/_pylibmcmodule.c        | 152 +++++++++++++++++++-------------------------
 src/_pylibmcmodule.h        |  25 ++++----
 src/pylibmc-version.h       |   2 +-
 src/pylibmc/__init__.py     |  11 +---
 src/pylibmc/client.py       |   8 ++-
 tests/test_client.py        |  17 +++++
 tests/test_refcounts.py     |  19 ++++++
 tests/test_serialization.py |   3 +-
 14 files changed, 267 insertions(+), 126 deletions(-)

diff --git a/MANIFEST.in b/MANIFEST.in
index 79a1587..c293df1 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,6 +3,6 @@ include src/_pylibmcmodule.c src/_pylibmcmodule.h src/pylibmc-version.h
 recursive-include pylibmc *.py
 recursive-include tests *.py
 
-include docs/Makefile docs/make.bat docs/conf.py
+include docs/Makefile docs/make.bat docs/conf.py docs/*.svg
 recursive-include docs *.rst
 recursive-include docs/_themes *
diff --git a/PKG-INFO b/PKG-INFO
index 9f33970..c292a68 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: pylibmc
-Version: 1.5.1
+Version: 1.5.2
 Summary: Quick and small memcached client for Python
 Home-page: http://sendapatch.se/projects/pylibmc/
 Author: Ludvig Ericson
@@ -79,3 +79,4 @@ Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.2
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
diff --git a/docs/failover.svg b/docs/failover.svg
new file mode 100644
index 0000000..dd497ce
--- /dev/null
+++ b/docs/failover.svg
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.26.3 (20100126.1600)
+ -->
+<!-- Title: G Pages: 1 -->
+<svg width="541pt" height="680pt"
+ viewBox="0.00 0.00 541.00 680.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 676)">
+<title>G</title>
+<!-- init -->
+<g id="node1" class="node"><title>init</title>
+<ellipse fill="lightgray" stroke="black" cx="453" cy="-654" rx="59.0322" ry="18"/>
+<text text-anchor="middle" x="453" y="-649.4" font-family="Times Roman,serif" font-size="14.00">new client</text>
+</g>
+<!-- initconnect -->
+<g id="node2" class="node"><title>initconnect</title>
+<ellipse fill="white" stroke="black" cx="453" cy="-566" rx="69.7653" ry="18"/>
+<text text-anchor="middle" x="453" y="-561.4" font-family="Times Roman,serif" font-size="14.00">first connect</text>
+</g>
+<!-- init->initconnect -->
+<g id="edge2" class="edge"><title>init->initconnect</title>
+<path fill="none" stroke="black" d="M453,-635.766C453,-623.849 453,-608.038 453,-594.482"/>
+<polygon fill="black" stroke="black" points="456.5,-594.21 453,-584.21 449.5,-594.21 456.5,-594.21"/>
+<text text-anchor="middle" x="488.5" y="-605.4" font-family="Times Roman,serif" font-size="14.00">on get/set</text>
+</g>
+<!-- connerr -->
+<g id="node3" class="node"><title>connerr</title>
+<ellipse fill="white" stroke="red" cx="360" cy="-492" rx="88.048" ry="18"/>
+<text text-anchor="middle" x="360" y="-487.4" font-family="Times Roman,serif" font-size="14.00">connection error</text>
+</g>
+<!-- initconnect->connerr -->
+<g id="edge4" class="edge"><title>initconnect->connerr</title>
+<path fill="none" stroke="black" d="M431.43,-548.837C419.166,-539.078 403.617,-526.706 390.159,-515.998"/>
+<polygon fill="black" stroke="black" points="392.103,-513.072 382.099,-509.584 387.745,-518.549 392.103,-513.072"/>
+</g>
+<!-- connected -->
+<g id="node9" class="node"><title>connected</title>
+<ellipse fill="white" stroke="black" cx="455" cy="-171" rx="59.8749" ry="18"/>
+<text text-anchor="middle" x="455" y="-166.4" font-family="Times Roman,serif" font-size="14.00">connected</text>
+</g>
+<!-- initconnect->connected -->
+<g id="edge8" class="edge"><title>initconnect->connected</title>
+<path fill="none" stroke="black" d="M469.039,-548.271C480.167,-534.104 493,-513.176 493,-492 493,-492 493,-492 493,-281 493,-252.317 488.711,-244.989 479,-218 476.582,-211.281 473.412,-204.297 470.172,-197.832"/>
+<polygon fill="black" stroke="black" points="473.194,-196.058 465.454,-188.823 466.993,-199.305 473.194,-196.058"/>
+</g>
+<!-- timeout -->
+<g id="node4" class="node"><title>timeout</title>
+<ellipse fill="white" stroke="red" cx="307" cy="-407" rx="99.201" ry="28.2843"/>
+<text text-anchor="middle" x="307" y="-410.4" font-family="Times Roman,serif" font-size="14.00">server has</text>
+<text text-anchor="middle" x="307" y="-394.4" font-family="Times Roman,serif" font-size="14.00">temporarily failed</text>
+</g>
+<!-- connerr->timeout -->
+<g id="edge6" class="edge"><title>connerr->timeout</title>
+<path fill="none" stroke="black" d="M348.76,-473.974C343.3,-465.217 336.529,-454.358 330.04,-443.95"/>
+<polygon fill="black" stroke="black" points="332.951,-442.004 324.69,-435.37 327.011,-445.708 332.951,-442.004"/>
+</g>
+<!-- server_dead -->
+<g id="node5" class="node"><title>server_dead</title>
+<ellipse fill="white" stroke="red" cx="178" cy="-281" rx="77.0746" ry="28.2843"/>
+<text text-anchor="middle" x="178" y="-284.4" font-family="Times Roman,serif" font-size="14.00">server is</text>
+<text text-anchor="middle" x="178" y="-268.4" font-family="Times Roman,serif" font-size="14.00">marked dead</text>
+</g>
+<!-- timeout->server_dead -->
+<g id="edge12" class="edge"><title>timeout->server_dead</title>
+<path fill="none" stroke="black" d="M224.479,-391.059C192.955,-383.15 162.314,-372.581 153,-360 143.872,-347.67 146.687,-331.904 153.079,-317.704"/>
+<polygon fill="black" stroke="black" points="156.271,-319.148 157.706,-308.651 150.038,-315.962 156.271,-319.148"/>
+<text text-anchor="middle" x="225.5" y="-347.4" font-family="Times Roman,serif" font-size="14.00">after remove_failed</text>
+<text text-anchor="middle" x="225.5" y="-331.4" font-family="Times Roman,serif" font-size="14.00">connection attempts</text>
+</g>
+<!-- new -->
+<g id="node8" class="node"><title>new</title>
+<ellipse fill="white" stroke="black" cx="349" cy="-281" rx="30.1869" ry="18"/>
+<text text-anchor="middle" x="349" y="-276.4" font-family="Times Roman,serif" font-size="14.00">new</text>
+</g>
+<!-- timeout->new -->
+<g id="edge16" class="edge"><title>timeout->new</title>
+<path fill="none" stroke="black" d="M302.681,-378.321C301.505,-362.919 301.929,-343.888 308,-328 311.52,-318.789 317.723,-310.184 324.256,-302.919"/>
+<polygon fill="black" stroke="black" points="326.909,-305.211 331.362,-295.597 321.886,-300.336 326.909,-305.211"/>
+<text text-anchor="middle" x="374.5" y="-347.4" font-family="Times Roman,serif" font-size="14.00">after retry_timeout</text>
+<text text-anchor="middle" x="374.5" y="-331.4" font-family="Times Roman,serif" font-size="14.00">(or dead_timeout)</text>
+</g>
+<!-- removed -->
+<g id="node6" class="node"><title>removed</title>
+<ellipse fill="white" stroke="red" cx="185" cy="-171" rx="89.8026" ry="28.2843"/>
+<text text-anchor="middle" x="185" y="-174.4" font-family="Times Roman,serif" font-size="14.00">server removed</text>
+<text text-anchor="middle" x="185" y="-158.4" font-family="Times Roman,serif" font-size="14.00">from rotation</text>
+</g>
+<!-- server_dead->removed -->
+<g id="edge14" class="edge"><title>server_dead->removed</title>
+<path fill="none" stroke="black" d="M179.821,-252.386C180.641,-239.501 181.622,-224.085 182.509,-210.152"/>
+<polygon fill="black" stroke="black" points="186.022,-210.055 183.164,-199.853 179.036,-209.61 186.022,-210.055"/>
+</g>
+<!-- added -->
+<g id="node7" class="node"><title>added</title>
+<ellipse fill="white" stroke="black" cx="104" cy="-29" rx="103.945" ry="28.2843"/>
+<text text-anchor="middle" x="104" y="-32.4" font-family="Times Roman,serif" font-size="14.00">server added back</text>
+<text text-anchor="middle" x="104" y="-16.4" font-family="Times Roman,serif" font-size="14.00">into rotation</text>
+</g>
+<!-- removed->added -->
+<g id="edge18" class="edge"><title>removed->added</title>
+<path fill="none" stroke="black" d="M168.997,-142.945C156.487,-121.014 138.982,-90.3265 125.29,-66.3226"/>
+<polygon fill="black" stroke="black" points="128.242,-64.4344 120.247,-57.4824 122.162,-67.9028 128.242,-64.4344"/>
+<text text-anchor="middle" x="226.5" y="-111.4" font-family="Times Roman,serif" font-size="14.00">after dead_timeout,</text>
+<text text-anchor="middle" x="226.5" y="-95.4" font-family="Times Roman,serif" font-size="14.00">make a single</text>
+<text text-anchor="middle" x="226.5" y="-79.4" font-family="Times Roman,serif" font-size="14.00">connection attempt</text>
+</g>
+<!-- added->timeout -->
+<g id="edge20" class="edge"><title>added->timeout</title>
+<path fill="none" stroke="black" d="M94.5567,-57.75C78.9475,-110.526 53.1425,-225.217 92,-310 112.627,-355.006 161.724,-379.137 207.799,-392.072"/>
+<polygon fill="black" stroke="black" points="207.011,-395.484 217.574,-394.666 208.806,-388.718 207.011,-395.484"/>
+</g>
+<!-- new->connected -->
+<g id="edge10" class="edge"><title>new->connected</title>
+<path fill="none" stroke="black" d="M351.392,-262.988C353.993,-249.358 359.311,-230.853 370,-218 379.899,-206.096 393.631,-196.686 407.173,-189.511"/>
+<polygon fill="black" stroke="black" points="409.067,-192.478 416.468,-184.898 405.955,-186.208 409.067,-192.478"/>
+<text text-anchor="middle" x="405.5" y="-221.4" font-family="Times Roman,serif" font-size="14.00">on get/set</text>
+</g>
+<!-- connected->timeout -->
+<g id="edge24" class="edge"><title>connected->timeout</title>
+<path fill="none" stroke="black" d="M459.578,-189.122C467.654,-225.641 480.117,-308.937 441,-360 433.982,-369.162 414.174,-377.908 391.87,-385.318"/>
+<polygon fill="black" stroke="black" points="390.65,-382.034 382.189,-388.41 392.78,-388.702 390.65,-382.034"/>
+</g>
+<!-- connected->connected -->
+<g id="edge22" class="edge"><title>connected->connected</title>
+<path fill="none" stroke="black" d="M504.887,-181.119C520.602,-180.965 533,-177.592 533,-171 533,-165.902 525.584,-162.729 514.952,-161.481"/>
+<polygon fill="black" stroke="black" points="515.078,-157.983 504.887,-160.881 514.661,-164.97 515.078,-157.983"/>
+</g>
+</g>
+</svg>
diff --git a/docs/install.rst b/docs/install.rst
index 887aa4a..cab21a2 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -5,7 +5,7 @@
 Requirements
 ============
 
-* Python 2.5 or later (Python 3 not supported yet)
+* Python 2.5, Python 3.2 or later
 * libmemcached 0.32 or later (last test with 1.0.18)
 * zlib (required for compression support)
 * libsasl2 (required for authentication support)
diff --git a/docs/reference.rst b/docs/reference.rst
index f223b3e..e2553ef 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -35,9 +35,10 @@
 
    .. Reading
 
-   .. method:: get(key) -> value
+   .. method:: get(key[, default]) -> value
 
-      Get *key* if it exists, otherwise ``None``.
+      Get *key* if it exists, otherwise *default*. If *default* is not given,
+      it defaults to ``None``.
 
    .. method:: get_multi(keys[, key_prefix=None]) -> values
 
@@ -160,29 +161,20 @@
 
    .. Deleting
 
-   .. method:: delete(key[, time=0]) -> deleted
+   .. method:: delete(key) -> deleted
 
       Delete *key* if it exists.
 
-      If *time* is non-zero, this is equivalent of setting an expiry time for a
-      key, i.e., the key will cease to exist after that many seconds.
-
       Returns ``True`` if the key was deleted, ``False`` otherwise (as is the case if
       it wasn't set in the first place.)
 
-      .. note:: Some versions of libmemcached are unable to set *time* for a
-                delete. This is true of versions up until at least 0.38.
-
-   .. method:: delete_multi(keys[, time=0, key_prefix=None]) -> deleted
+   .. method:: delete_multi(keys[, key_prefix=None]) -> deleted
 
       Delete each of key in the sequence *keys*.
 
       :param keys: Sequence of keys to delete
-      :param time: Number of seconds until the keys are deleted
       :param key_prefix: Prefix for the keys to delete
 
-      If *time* is zero, the keys are deleted immediately.
-
       Returns ``True`` if all keys were successfully deleted, ``False``
       otherwise (as is the case if it wasn't set in the first place.)
 
diff --git a/setup.py b/setup.py
index 7de01aa..f6a5180 100644
--- a/setup.py
+++ b/setup.py
@@ -121,5 +121,6 @@ setup(
         'Programming Language :: Python :: 3.2',
         'Programming Language :: Python :: 3.3',
         'Programming Language :: Python :: 3.4',
+        'Programming Language :: Python :: 3.5',
     ],
 )
diff --git a/src/_pylibmcmodule.c b/src/_pylibmcmodule.c
index 1372144..1ce5a6a 100644
--- a/src/_pylibmcmodule.c
+++ b/src/_pylibmcmodule.c
@@ -304,8 +304,8 @@ error:
 
 /* {{{ Compression helpers */
 #ifdef USE_ZLIB
-static int _PylibMC_Deflate(char *value, size_t value_len,
-                    char **result, size_t *result_len,
+static int _PylibMC_Deflate(char *value, Py_ssize_t value_len,
+                    char **result, Py_ssize_t *result_len,
                     int compress_level) {
     /* FIXME Failures are entirely silent. */
     int rc;
@@ -373,8 +373,8 @@ error:
     return 0;
 }
 
-static int _PylibMC_Inflate(char *value, size_t size,
-                            char** result, size_t* result_size,
+static int _PylibMC_Inflate(char *value, Py_ssize_t size,
+                            char** result, Py_ssize_t* result_size,
                             char** failure_reason) {
 
     /*
@@ -542,7 +542,7 @@ static void _PylibMC_cleanup_str_key_mapping(PyObject *key_str_map) {
 /* }}} */
 
 static PyObject *_PylibMC_parse_memcached_value(PylibMC_Client *self,
-        char *value, size_t size, uint32_t flags) {
+        char *value, Py_ssize_t size, uint32_t flags) {
     PyObject *retval = NULL;
 
 #if USE_ZLIB
@@ -552,7 +552,7 @@ static PyObject *_PylibMC_parse_memcached_value(PylibMC_Client *self,
     if (flags & PYLIBMC_FLAG_ZLIB) {
         int rc;
         char* inflated_buf = NULL;
-        size_t inflated_size = 0;
+        Py_ssize_t inflated_size = 0;
         char* failure_reason = NULL;
 
         if(size >= ZLIB_GIL_RELEASE) {
@@ -618,7 +618,7 @@ static PyObject *_PylibMC_parse_memcached_value(PylibMC_Client *self,
 }
 
 /** Helper because PyLong_FromString requires a null-terminated string. */
-static PyObject *_PyLong_FromStringAndSize(char *value, size_t size, char **pend, int base) {
+static PyObject *_PyLong_FromStringAndSize(char *value, Py_ssize_t size, char **pend, int base) {
     PyObject *retval;
     char *tmp;
     if ((tmp = malloc(size+1)) == NULL) {
@@ -637,7 +637,7 @@ static PyObject *_PyLong_FromStringAndSize(char *value, size_t size, char **pend
   the value to be deserialized is a byte array `value_str` of length
   `value_size`.
   */
-static PyObject *_PylibMC_deserialize_native(PylibMC_Client *self, PyObject *value, char *value_str, size_t value_size, uint32_t flags) {
+static PyObject *_PylibMC_deserialize_native(PylibMC_Client *self, PyObject *value, char *value_str, Py_ssize_t value_size, uint32_t flags) {
     assert(value || value_str);
     PyObject *retval = NULL;
 
@@ -707,47 +707,54 @@ static int _PylibMC_cache_miss_simulated(PyObject *r) {
     return 0;
 }
 
-static PyObject *PylibMC_Client_get(PylibMC_Client *self, PyObject *arg) {
+static PyObject *PylibMC_Client_get(PylibMC_Client *self, PyObject *args) {
     char *mc_val;
     size_t val_size;
     uint32_t flags;
     memcached_return error;
+    PyObject *key;
+    /* if a default argument was in fact passed, it's still a borrowed reference
+       at this point, so borrow a reference to Py_None as well for parity. */
+    PyObject *default_value = Py_None;
 
-    if (!_key_normalized_obj(&arg)) {
+    if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_value)) {
+        return NULL;
+    }
+
+    if (!_key_normalized_obj(&key)) {
         return NULL;
-    } else if (!PySequence_Length(arg) ) {
-        Py_RETURN_NONE;
+    } else if (!PySequence_Length(key) ) {
+        Py_INCREF(default_value);
+        return default_value;
     }
 
     Py_BEGIN_ALLOW_THREADS;
     mc_val = memcached_get(self->mc,
-            PyBytes_AS_STRING(arg), PyBytes_GET_SIZE(arg),
+            PyBytes_AS_STRING(key), PyBytes_GET_SIZE(key),
             &val_size, &flags, &error);
     Py_END_ALLOW_THREADS;
 
-    Py_DECREF(arg);
+    Py_DECREF(key);
 
     if (mc_val != NULL) {
         PyObject *r = _PylibMC_parse_memcached_value(self, mc_val, val_size, flags);
         free(mc_val);
         if (_PylibMC_cache_miss_simulated(r)) {
-            /* Since python-memcache returns None when the key doesn't exist,
-             * so shall we. */
-            Py_RETURN_NONE;
+            Py_INCREF(default_value);
+            return default_value;
         }
         return r;
     } else if (error == MEMCACHED_SUCCESS) {
         /* This happens for empty values, and so we fake an empty string. */
         return PyBytes_FromStringAndSize("", 0);
     } else if (error == MEMCACHED_NOTFOUND) {
-        /* Since python-memcache returns None when the key doesn't exist,
-         * so shall we. */
-        Py_RETURN_NONE;
+        Py_INCREF(default_value);
+        return default_value;
     }
 
     return PylibMC_ErrFromMemcachedWithKey(self, "memcached_get", error,
-                                           PyBytes_AS_STRING(arg),
-                                           PyBytes_GET_SIZE(arg));
+                                           PyBytes_AS_STRING(key),
+                                           PyBytes_GET_SIZE(key));
 }
 
 static PyObject *PylibMC_Client_gets(PylibMC_Client *self, PyObject *arg) {
@@ -829,7 +836,7 @@ static PyObject *PylibMC_Client_hash(PylibMC_Client *self, PyObject *args, PyObj
         return NULL;
     }
 
-    h = memcached_generate_hash(self->mc, key, (size_t)key_len);
+    h = memcached_generate_hash(self->mc, key, (Py_ssize_t)key_len);
 
     return PyLong_FromLong((long)h);
 }
@@ -922,11 +929,11 @@ static PyObject *_PylibMC_RunSetCommandMulti(PylibMC_Client *self,
     unsigned int min_compress = 0;
     int compress_level = -1;
     PyObject *failed = NULL;
-    size_t idx = 0;
+    Py_ssize_t idx = 0;
     PyObject *curr_key, *curr_value;
     PyObject *key_str_map = NULL;
     Py_ssize_t i;
-    size_t nkeys;
+    Py_ssize_t nkeys;
     pylibmc_mset* serialized = NULL;
     bool allsuccess;
 
@@ -955,7 +962,7 @@ static PyObject *_PylibMC_RunSetCommandMulti(PylibMC_Client *self,
     }
 #endif
 
-    nkeys = (size_t)PyDict_Size(keys);
+    nkeys = (Py_ssize_t)PyDict_Size(keys);
 
     key_str_map = _PylibMC_map_str_keys(keys, NULL, NULL);
     if (key_str_map == NULL) {
@@ -1294,8 +1301,8 @@ static PyObject *PylibMC_Client_serialize(PylibMC_Client *self, PyObject *value_
 /* {{{ Set commands (set, replace, add, prepend, append) */
 static bool _PylibMC_RunSetCommand(PylibMC_Client* self,
                                    _PylibMC_SetCommand f, char *fname,
-                                   pylibmc_mset* msets, size_t nkeys,
-                                   size_t min_compress,
+                                   pylibmc_mset* msets, Py_ssize_t nkeys,
+                                   Py_ssize_t min_compress,
                                    int compress_level) {
     memcached_st *mc = self->mc;
     memcached_return rc = MEMCACHED_SUCCESS;
@@ -1309,12 +1316,12 @@ static bool _PylibMC_RunSetCommand(PylibMC_Client* self,
         pylibmc_mset *mset = &msets[i];
 
         char *value = mset->value;
-        size_t value_len = (size_t)mset->value_len;
+        Py_ssize_t value_len = (Py_ssize_t)mset->value_len;
         uint32_t flags = mset->flags;
 
 #ifdef USE_ZLIB
         char *compressed_value = NULL;
-        size_t compressed_len = 0;
+        Py_ssize_t compressed_len = 0;
 
         if (compress_level && min_compress && value_len >= min_compress) {
             _PylibMC_Deflate(value, value_len,
@@ -1501,11 +1508,6 @@ static PyObject *_PylibMC_IncrSingle(PylibMC_Client *self,
         return NULL;
     }
 
-    if ((unsigned int)delta != delta) {
-        PyErr_Format(PyExc_OverflowError, "%d", delta);
-        return NULL;
-    }
-
     incr.key = key;
     incr.key_len = key_len;
     incr.incr_func = incr_func;
@@ -1535,7 +1537,7 @@ static PyObject *_PylibMC_IncrMulti(PylibMC_Client *self,
     PyObject *retval = NULL;
     PyObject *iterator = NULL;
     unsigned int delta = 1;
-    size_t nkeys = 0, i = 0;
+    Py_ssize_t nkeys = 0, i = 0;
     pylibmc_incr *incrs;
 
     static char *kws[] = { "keys", "key_prefix", "delta", NULL };
@@ -1545,7 +1547,7 @@ static PyObject *_PylibMC_IncrMulti(PylibMC_Client *self,
                                      &key_prefix_len, &delta))
         return NULL;
 
-    nkeys = (size_t)PySequence_Size(keys);
+    nkeys = (Py_ssize_t)PySequence_Size(keys);
     if (nkeys == -1)
         return NULL;
 
@@ -1638,10 +1640,10 @@ static PyObject *PylibMC_Client_incr_multi(PylibMC_Client *self, PyObject *args,
 }
 
 static bool _PylibMC_IncrDecr(PylibMC_Client *self,
-                              pylibmc_incr *incrs, size_t nkeys) {
+                              pylibmc_incr *incrs, Py_ssize_t nkeys) {
     memcached_return rc = MEMCACHED_SUCCESS;
     _PylibMC_IncrCommand f = NULL;
-    size_t i, notfound = 0, errors = 0;
+    Py_ssize_t i, notfound = 0, errors = 0;
 
     Py_BEGIN_ALLOW_THREADS;
     for (i = 0; i < nkeys; i++) {
@@ -1757,7 +1759,7 @@ static PyObject *PylibMC_Client_get_multi(
     PyObject *temp_key_obj;
     size_t *key_lens;
     Py_ssize_t nkeys = 0, orig_nkeys = 0;
-    size_t nresults = 0;
+    Py_ssize_t nresults = 0;
     memcached_return rc;
     pylibmc_mget_req req;
 
@@ -1773,8 +1775,8 @@ static PyObject *PylibMC_Client_get_multi(
     /* Populate keys and key_lens. */
     keys = PyMem_New(char *, orig_nkeys);
     key_lens = PyMem_New(size_t, (size_t) orig_nkeys);
-    key_objs = PyMem_New(PyObject *, (size_t) orig_nkeys);
-    orig_key_objs = PyMem_New(PyObject *, (size_t) orig_nkeys);
+    key_objs = PyMem_New(PyObject *, (Py_ssize_t) orig_nkeys);
+    orig_key_objs = PyMem_New(PyObject *, (Py_ssize_t) orig_nkeys);
     if (!keys || !key_lens || !key_objs || !orig_key_objs) {
         PyErr_NoMemory();
         goto memory_cleanup;
@@ -1795,7 +1797,7 @@ static PyObject *PylibMC_Client_get_multi(
         PyObject *ckey = orig_key_objs[i];
         char *key;
         Py_ssize_t key_len;
-        size_t final_key_len;
+        Py_ssize_t final_key_len;
         PyObject *rkey;
 
         if (PyErr_Occurred() || !_key_normalized_obj(&ckey)) {
@@ -1807,7 +1809,7 @@ static PyObject *PylibMC_Client_get_multi(
 
         PyBytes_AsStringAndSize(ckey, &key, &key_len);
 
-        final_key_len = (size_t)(key_len + prefix_len);
+        final_key_len = (Py_ssize_t)(key_len + prefix_len);
 
         /* Skip empty keys */
         if (!final_key_len) {
@@ -2067,10 +2069,8 @@ static PyObject *PylibMC_Client_delete_multi(PylibMC_Client *self,
     const char *prefix_raw = NULL;
     Py_ssize_t prefix_len;
     PyObject *prefix = NULL;
-    PyObject *time = NULL;
     PyObject *delete;
     PyObject *keys;
-    PyObject *call_args;
     PyObject *retval;
 
     static char *kws[] = { "keys", "key_prefix", NULL };
@@ -2080,48 +2080,25 @@ static PyObject *PylibMC_Client_delete_multi(PylibMC_Client *self,
         return NULL;
 
     /**
-     * Because of how DoMulti works, we have to prohibit the use of mappings
-     * here. Otherwise, the values of the mapping will be the second argument
-     * to the delete function; the time argument will then become a third
-     * argument, which delete doesn't take.
-     *
-     * So a mapping to DoMulti would produce calls like:
-     *   DoMulti({"a": 1, "b": 2}, time=3)
-     *      delete("a", 1, 3)
-     *      delete("b", 2, 3)
-     */
-#if PY_MAJOR_VERSION >= 3
-    /*
-     * This isn't optimal, but PyMapping_Check returns 1 for
-     * tuples, lists and other sequences in Python 3. According to
-     * http://bugs.python.org/issue5945 PyMapping_Check has never
-     * been particularly reliable, so hopefully it's enough to
-     * check for dict objects (and subclasses) specifically.
+     * Prohibit use of mappings, otherwise DoMulti interprets the values of
+     * such mappings as the 2nd argument to the delete function, e.g.
+     * DoMulti({"a": 1, "b": 2}) calls delete("a", 1) and delete("b", 2), which
+     * is nonsense.
      */
     if (PyDict_Check(keys)) {
-#else
-    if (PyMapping_Check(keys)) {
-#endif
         PyErr_SetString(PyExc_TypeError,
             "keys must be a sequence, not a mapping");
         return NULL;
     }
 
-    if (prefix_raw != NULL) {
+    if (prefix_raw != NULL)
         prefix = PyBytes_FromStringAndSize(prefix_raw, prefix_len);
-    }
 
     if ((delete = PyObject_GetAttrString((PyObject *)self, "delete")) == NULL)
         return NULL;
 
-    if (time == NULL) {
-        retval = _PylibMC_DoMulti(keys, delete, prefix, NULL);
-    } else {
-        if ((call_args = PyTuple_Pack(1, time)) == NULL)
-            goto error;
-        retval = _PylibMC_DoMulti(keys, delete, prefix, call_args);
-        Py_DECREF(call_args);
-    }
+    retval = _PylibMC_DoMulti(keys, delete, prefix, NULL);
+
     Py_DECREF(delete);
     Py_XDECREF(prefix);
 
@@ -2135,12 +2112,9 @@ static PyObject *PylibMC_Client_delete_multi(PylibMC_Client *self,
         Py_DECREF(retval);
         retval = Py_False;
     }
-    Py_INCREF(retval);
 
+    Py_INCREF(retval);
     return retval;
-error:
-    Py_XDECREF(delete);
-    return NULL;
 }
 
 static PyObject *PylibMC_Client_get_behaviors(PylibMC_Client *self) {
@@ -2438,10 +2412,18 @@ static void _set_error(memcached_st *mc, memcached_return error, char *lead) {
                      lead, strerror(errno));
     } else if (error == MEMCACHED_SUCCESS) {
         PyErr_Format(PyExc_RuntimeError, "error == MEMCACHED_SUCCESS");
+#if LIBMEMCACHED_VERSION_HEX >= 0x01000002
+    } else if (error == MEMCACHED_E2BIG) {
+        PyErr_SetNone(_exc_by_rc(error));
+#endif
     } else {
         PyObject *exc = _exc_by_rc(error);
 #if LIBMEMCACHED_VERSION_HEX >= 0x00049000
-        PyErr_Format(exc, "%s: %.200s", lead, memcached_last_error_message(mc));
+        if (memcached_last_error(mc) != MEMCACHED_SUCCESS) {
+            PyErr_Format(exc, "%s: %.200s", lead, memcached_last_error_message(mc));
+        } else {
+            PyErr_SetString(exc, lead);
+        }
 #else
         PyErr_Format(exc, "%s: %.200s", lead, memcached_strerror(mc, error));
 #endif
@@ -2489,7 +2471,7 @@ static PyObject *_PylibMC_GetPickles(const char *attname) {
     return pickle_attr;
 }
 
-static PyObject *_PylibMC_Unpickle(const char *buff, size_t size) {
+static PyObject *_PylibMC_Unpickle(const char *buff, Py_ssize_t size) {
 #if PY_MAJOR_VERSION >= 3
         return PyObject_CallFunction(_PylibMC_pickle_loads, "y#", buff, size);
 #else
@@ -2502,7 +2484,7 @@ static PyObject *_PylibMC_Unpickle_Bytes(PyObject *val) {
 }
 
 static PyObject *_PylibMC_Pickle(PyObject *val) {
-    return PyObject_CallFunctionObjArgs(_PylibMC_pickle_dumps, val, NULL);
+    return PyObject_CallFunction(_PylibMC_pickle_dumps, "Oi", val, -1);
 }
 /* }}} */
 
@@ -2660,7 +2642,7 @@ static void _make_excs(PyObject *module) {
             "pylibmc.Error", NULL, NULL);
 
     PylibMCExc_CacheMiss = PyErr_NewException(
-            "_pylibmc.CacheMiss", PylibMCExc_Error, NULL);
+            "pylibmc.CacheMiss", PylibMCExc_Error, NULL);
 
     exc_objs = PyList_New(0);
     PyList_Append(exc_objs,
@@ -2670,7 +2652,7 @@ static void _make_excs(PyObject *module) {
 
     for (err = PylibMCExc_mc_errs; err->name != NULL; err++) {
         char excnam[64];
-        snprintf(excnam, 64, "_pylibmc.%s", err->name);
+        snprintf(excnam, 64, "pylibmc.%s", err->name);
         err->exc = PyErr_NewException(excnam, PylibMCExc_Error, NULL);
         PyObject_SetAttrString(err->exc, "retcode", PyLong_FromLong(err->rc));
         PyModule_AddObject(module, err->name, (PyObject *)err->exc);
diff --git a/src/_pylibmcmodule.h b/src/_pylibmcmodule.h
index b3847ab..3aa3dcc 100644
--- a/src/_pylibmcmodule.h
+++ b/src/_pylibmcmodule.h
@@ -105,10 +105,10 @@ typedef struct {
 
 typedef struct {
   char **keys;
-  size_t nkeys;
+  Py_ssize_t nkeys;
   size_t *key_lens;
   memcached_result_st **results;
-  size_t *nresults;
+  Py_ssize_t *nresults;
   char **err_func;
   PyObject *transform;
 } pylibmc_mget_req;
@@ -177,6 +177,7 @@ static PylibMC_McErr PylibMCExc_mc_errs[] = {
     { MEMCACHED_SERVER_MARKED_DEAD, "ServerDead", NULL },
 #if LIBMEMCACHED_VERSION_HEX >= 0x01000002
     { MEMCACHED_SERVER_TEMPORARILY_DISABLED, "ServerDown", NULL },
+    { MEMCACHED_E2BIG, "TooBig", NULL },
 #endif
     { MEMCACHED_UNKNOWN_STAT_KEY, "UnknownStatKey", NULL },
     //{ MEMCACHED_E2BIG, "TooBigError", NULL },
@@ -314,14 +315,14 @@ static PyObject *PylibMC_ErrFromMemcachedWithKey(PylibMC_Client *, const char *,
         memcached_return, const char *, Py_ssize_t);
 static PyObject *PylibMC_ErrFromMemcached(PylibMC_Client *, const char *,
         memcached_return);
-static PyObject *_PylibMC_Unpickle(const char *, size_t);
+static PyObject *_PylibMC_Unpickle(const char *, Py_ssize_t);
 static PyObject *_PylibMC_Unpickle_Bytes(PyObject *);
 static PyObject *_PylibMC_Pickle(PyObject *);
 static int _key_normalized_obj(PyObject **);
 static int _key_normalized_str(char **, Py_ssize_t *);
 static int _PylibMC_serialize_user(PylibMC_Client *, PyObject *, PyObject **, uint32_t *);
 static int _PylibMC_serialize_native(PylibMC_Client *, PyObject *, PyObject **, uint32_t *);
-static PyObject *_PylibMC_deserialize_native(PylibMC_Client *, PyObject *, char *, size_t, uint32_t);
+static PyObject *_PylibMC_deserialize_native(PylibMC_Client *, PyObject *, char *, Py_ssize_t, uint32_t);
 static int _PylibMC_SerializeValue(PylibMC_Client *self,
                                    PyObject *key_obj,
                                    PyObject *key_prefix,
@@ -335,16 +336,16 @@ static PyObject *_PylibMC_RunSetCommandMulti(PylibMC_Client *self,
         _PylibMC_SetCommand f, char *fname, PyObject *args, PyObject *kwds);
 static bool _PylibMC_RunSetCommand(PylibMC_Client *self,
                                    _PylibMC_SetCommand f, char *fname,
-                                   pylibmc_mset *msets, size_t nkeys,
-                                   size_t min_compress,
+                                   pylibmc_mset *msets, Py_ssize_t nkeys,
+                                   Py_ssize_t min_compress,
                                    int compress_level);
-static int _PylibMC_Deflate(char *value, size_t value_len,
-                            char **result, size_t *result_len,
+static int _PylibMC_Deflate(char *value, Py_ssize_t value_len,
+                            char **result, Py_ssize_t *result_len,
                             int compress_level);
-static int _PylibMC_Inflate(char *value, size_t size,
-                            char** result, size_t* result_size,
+static int _PylibMC_Inflate(char *value, Py_ssize_t size,
+                            char** result, Py_ssize_t* result_size,
                             char** failure_reason);
-static bool _PylibMC_IncrDecr(PylibMC_Client *, pylibmc_incr *, size_t);
+static bool _PylibMC_IncrDecr(PylibMC_Client *, pylibmc_incr *, Py_ssize_t);
 
 /* }}} */
 
@@ -356,7 +357,7 @@ static PyMethodDef PylibMC_ClientType_methods[] = {
     {"deserialize", (PyCFunction)PylibMC_Client_deserialize, METH_VARARGS,
         "Deserialize a bytestring and flag field retrieved from memcached. "
         "Raise pylibmc.CacheMiss to simulate a cache miss."},
-    {"get", (PyCFunction)PylibMC_Client_get, METH_O,
+    {"get", (PyCFunction)PylibMC_Client_get, METH_VARARGS,
         "Retrieve a key from a memcached."},
     {"gets", (PyCFunction)PylibMC_Client_gets, METH_O,
         "Retrieve a key and cas_id from a memcached."},
diff --git a/src/pylibmc-version.h b/src/pylibmc-version.h
index 932ac03..4a4a5aa 100644
--- a/src/pylibmc-version.h
+++ b/src/pylibmc-version.h
@@ -1 +1 @@
-#define PYLIBMC_VERSION "1.5.1"
+#define PYLIBMC_VERSION "1.5.2"
diff --git a/src/pylibmc/__init__.py b/src/pylibmc/__init__.py
index 286f551..b4f51ba 100644
--- a/src/pylibmc/__init__.py
+++ b/src/pylibmc/__init__.py
@@ -69,17 +69,12 @@ See http://sendapatch.se/projects/pylibmc/
 """
 
 import _pylibmc
+from _pylibmc import *
+from _pylibmc import __version__
 from .consts import hashers, distributions
 from .client import Client
 from .pools import ClientPool, ThreadMappedPool
 
-libmemcached_version = _pylibmc.libmemcached_version
-support_compression = _pylibmc.support_compression
-support_sasl = _pylibmc.support_sasl
-Error = _pylibmc.Error
-
-__version__ = _pylibmc.__version__
-
 def build_info():
     return ("pylibmc %s for libmemcached %s (compression=%s, sasl=%s)"
             % (__version__,
@@ -88,4 +83,4 @@ def build_info():
                support_sasl))
 
 __all__ = ["hashers", "distributions", "Client",
-           "ClientPool", "ThreadMappedPool"]
+           "ClientPool", "ThreadMappedPool"] + dir(_pylibmc)
diff --git a/src/pylibmc/client.py b/src/pylibmc/client.py
index c93016a..e2da11e 100644
--- a/src/pylibmc/client.py
+++ b/src/pylibmc/client.py
@@ -12,6 +12,8 @@ server_type_map = {"tcp":   _pylibmc.server_type_tcp,
                    "udp":   _pylibmc.server_type_udp,
                    "unix":  _pylibmc.server_type_unix}
 
+_MISS_SENTINEL = object()
+
 def _split_spec_type(spec):
     if spec.startswith("/"):
         return ("unix", spec)
@@ -153,8 +155,8 @@ class Client(_pylibmc.client):
 
     # {{{ Mapping interface
     def __getitem__(self, key):
-        value = self.get(key)
-        if value is None:
+        value = self.get(key, _MISS_SENTINEL)
+        if value is _MISS_SENTINEL:
             raise KeyError(key)
         else:
             return value
@@ -168,7 +170,7 @@ class Client(_pylibmc.client):
             raise KeyError(key)
 
     def __contains__(self, key):
-        return self.get(key) is not None
+        return self.get(key, _MISS_SENTINEL) is not _MISS_SENTINEL
     # }}}
 
     # {{{ Behaviors
diff --git a/tests/test_client.py b/tests/test_client.py
index 3a61fea..6636f40 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -94,3 +94,20 @@ class ClientTests(PylibmcTestCase):
         mc = make_test_client(binary=True)
         ok_(mc.set(k, 0))
         ok_(mc.get(k_enc) == 0)
+
+    def test_get_with_default(self):
+        mc = make_test_client(binary=True)
+        key = 'get-api-test'
+        mc.delete(key)
+        eq_(mc.get(key), None)
+        default = object()
+        assert mc.get(key, default) is default
+
+    def test_none_values(self):
+        mc = make_test_client(binary=True)
+        mc.set('none-test', None)
+        self.assertEqual(mc.get('none-test'), None)
+        self.assertEqual(mc.get('none-test', 'default'), None)
+        # formerly, this would raise a KeyError, which was incorrect
+        self.assertEqual(mc['none-test'], None)
+        assert 'none-test' in mc
diff --git a/tests/test_refcounts.py b/tests/test_refcounts.py
index 92a5ac6..699bbd7 100644
--- a/tests/test_refcounts.py
+++ b/tests/test_refcounts.py
@@ -47,6 +47,25 @@ class RefcountTests(PylibmcTestCase):
     def test_get_singleton(self):
         self._test_get(b"refcountest3", False)
 
+    def test_get_with_default(self):
+        bc = make_test_client(binary=True)
+        key = b'refcountest4'
+        val = 'some_value'
+        default = object()
+        refcountables = [key, val, default]
+        initial_refcounts = get_refcounts(refcountables)
+        bc.set(key, val)
+        eq_(get_refcounts(refcountables), initial_refcounts)
+        assert bc.get(key) == val
+        eq_(get_refcounts(refcountables), initial_refcounts)
+        assert bc.get(key, default) == val
+        eq_(get_refcounts(refcountables), initial_refcounts)
+        bc.delete(key)
+        assert bc.get(key) is None
+        eq_(get_refcounts(refcountables), initial_refcounts)
+        assert bc.get(key, default) is default
+        eq_(get_refcounts(refcountables), initial_refcounts)
+
     def test_get_multi(self):
         bc = make_test_client(binary=True)
         keys = ["first", "second", "", b""]
diff --git a/tests/test_serialization.py b/tests/test_serialization.py
index 4a1f8c7..61f2e57 100644
--- a/tests/test_serialization.py
+++ b/tests/test_serialization.py
@@ -53,7 +53,8 @@ class SerializationMethodTests(PylibmcTestCase):
             (b'asdf', (b'asdf', 0)),
             (b'\xb5\xb1\xbf\xed\xa9\xc2{8', (b'\xb5\xb1\xbf\xed\xa9\xc2{8', 0)),
             # objects
-            (datetime.date(2015, 12, 28), (pickle.dumps(datetime.date(2015, 12, 28)), 1)),
+            (datetime.date(2015, 12, 28), (pickle.dumps(datetime.date(2015, 12, 28),
+                                                        protocol=-1), 1)),
         ]
 
         c = make_test_client(binary=True)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pylibmc.git



More information about the Python-modules-commits mailing list