Hello community,
here is the log from the commit of package python-pylibmc for
openSUSE:Leap:15.2 checked in at 2020-02-21 23:48:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Leap:15.2/python-pylibmc (Old)
and /work/SRC/openSUSE:Leap:15.2/.python-pylibmc.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pylibmc"
Fri Feb 21 23:48:46 2020 rev:11 rq:776984 version:1.6.1
Changes:
--------
--- /work/SRC/openSUSE:Leap:15.2/python-pylibmc/python-pylibmc.changes
2020-01-15 15:52:00.319548448 +0100
+++
/work/SRC/openSUSE:Leap:15.2/.python-pylibmc.new.26092/python-pylibmc.changes
2020-02-21 23:48:47.284499279 +0100
@@ -1,0 +2,15 @@
+Tue Sep 10 12:04:16 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 1.6.1:
+ * no changelog provided
+
+-------------------------------------------------------------------
+Tue Mar 12 05:07:50 UTC 2019 - John Vandenberg <[email protected]>
+
+- Remove bcond test
+- Activate test suite
+- Use %license
+- Update URL to GitHub repository
+- Update to v1.6.0
+
+-------------------------------------------------------------------
Old:
----
pylibmc-1.5.2.tar.gz
New:
----
pylibmc-1.6.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pylibmc.spec ++++++
--- /var/tmp/diff_new_pack.dqtNdm/_old 2020-02-21 23:48:47.644499994 +0100
+++ /var/tmp/diff_new_pack.dqtNdm/_new 2020-02-21 23:48:47.644499994 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-pylibmc
#
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -12,29 +12,27 @@
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
-%bcond_with test
Name: python-pylibmc
-Version: 1.5.2
+Version: 1.6.1
Release: 0
Summary: memcached client for Python
License: BSD-3-Clause
Group: Development/Languages/Python
-Url: http://sendapatch.se/projects/pylibmc/
+URL: https://github.com/lericson/pylibmc
Source:
https://files.pythonhosted.org/packages/source/p/pylibmc/pylibmc-%{version}.tar.gz
BuildRequires: %{python_module devel}
+BuildRequires: %{python_module nose}
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: libmemcached-devel
+BuildRequires: memcached
BuildRequires: python-rpm-macros
BuildRequires: zlib-devel
-%if %{with test}
-BuildRequires: %{python_module nose}
-%endif
%python_subpackages
%description
@@ -56,17 +54,18 @@
%python_install
%python_expand %fdupes %{buildroot}%{$python_sitearch}
-%if %{with test}
%check
+%{_sbindir}/memcached &
+pid=$!
export NOSE_IGNORE_CONFIG_FILES=1
%{python_expand export PYTHONPATH=%{buildroot}%{$python_sitearch}
nosetests-%{$python_bin_suffix} tests
}
-%endif
+kill $pid
%files %{python_files}
-%defattr(-,root,root,-)
-%doc LICENSE README.rst
+%license LICENSE
+%doc README.rst
%{python_sitearch}/*
%changelog
++++++ pylibmc-1.5.2.tar.gz -> pylibmc-1.6.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/PKG-INFO new/pylibmc-1.6.1/PKG-INFO
--- old/pylibmc-1.5.2/PKG-INFO 2017-03-06 14:13:31.000000000 +0100
+++ new/pylibmc-1.6.1/PKG-INFO 2019-08-15 14:04:10.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pylibmc
-Version: 1.5.2
+Version: 1.6.1
Summary: Quick and small memcached client for Python
Home-page: http://sendapatch.se/projects/pylibmc/
Author: Ludvig Ericson
@@ -15,6 +15,22 @@
.. image:: https://travis-ci.org/lericson/pylibmc.png?branch=master
:target: https://travis-ci.org/lericson/pylibmc
+ New in version 1.6.0
+ ====================
+
+ Though no major feature overhauls have taken place, this release is
partially
+ incompatible with 1.5.0. This stems from the fact that
python-memcached is now
+ using a flag that pylibmc has been using for some years.
python-memcached uses
+ it for a different purpose, and an incompatible one. We deemed that it
would be
+ better to support this interoperability. The change also means that
Unicode
+ strings are now stored as UTF-8 rather than pickled, which may or may
not
+ result in a slight performance improvement for this type of data.
+
+ We have also introduced a `pickle_protocol` behavior to enable seamless
+ interoperability between Python 2.x and 3.x. Also, this release
introduces a
+ ManyLinux wheel, making installation a breeze on ManyLinux systems
(which I
+ suppose is many linuxes.)
+
New in version 1.5.0
====================
@@ -80,3 +96,5 @@
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/README.rst new/pylibmc-1.6.1/README.rst
--- old/pylibmc-1.5.2/README.rst 2016-03-21 19:38:38.000000000 +0100
+++ new/pylibmc-1.6.1/README.rst 2018-11-09 18:49:56.000000000 +0100
@@ -7,6 +7,22 @@
.. image:: https://travis-ci.org/lericson/pylibmc.png?branch=master
:target: https://travis-ci.org/lericson/pylibmc
+New in version 1.6.0
+====================
+
+Though no major feature overhauls have taken place, this release is partially
+incompatible with 1.5.0. This stems from the fact that python-memcached is now
+using a flag that pylibmc has been using for some years. python-memcached uses
+it for a different purpose, and an incompatible one. We deemed that it would be
+better to support this interoperability. The change also means that Unicode
+strings are now stored as UTF-8 rather than pickled, which may or may not
+result in a slight performance improvement for this type of data.
+
+We have also introduced a `pickle_protocol` behavior to enable seamless
+interoperability between Python 2.x and 3.x. Also, this release introduces a
+ManyLinux wheel, making installation a breeze on ManyLinux systems (which I
+suppose is many linuxes.)
+
New in version 1.5.0
====================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/docs/behaviors.rst
new/pylibmc-1.6.1/docs/behaviors.rst
--- old/pylibmc-1.5.2/docs/behaviors.rst 2015-09-28 18:38:56.000000000
+0200
+++ new/pylibmc-1.6.1/docs/behaviors.rst 2018-11-09 18:42:08.000000000
+0100
@@ -250,3 +250,18 @@
``auto_eject``; these still exist, but their interaction with the
state machine is unclear, and should be avoided. ``remove_failed``
acts as a combination of the two.
+
+Non-libmemcached Behaviors
+--------------------------
+
+It wouldn't make sense to have multiple avenues of configuration, and so
+whenever possible, pylibmc tries to co-opt the behaviors dictionary for
+configuration of strictly pylibmc-level things. These are described below.
+
+.. _pickle_protocol:
+
+``"pickle_protocol"``
+ Specifies the default pickling protocol. This is by default set to -1, which
+ means the pickle module will use the latest protocol it understands. This is
+ an issue for interoperability, and so for example to work between Python 2
+ and 3, set this explicitly to 2 or whatever you prefer.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/docs/changelog.rst
new/pylibmc-1.6.1/docs/changelog.rst
--- old/pylibmc-1.5.2/docs/changelog.rst 2016-03-21 19:37:17.000000000
+0100
+++ new/pylibmc-1.6.1/docs/changelog.rst 2018-11-09 19:35:16.000000000
+0100
@@ -1,6 +1,22 @@
Change Log
==========
+New in version 1.6.0
+--------------------
+
+Though no major feature overhauls have taken place, this release is partially
+incompatible with 1.5.0. This stems from the fact that python-memcached is now
+using a flag that pylibmc has been using for some years. python-memcached uses
+it for a different purpose, and an incompatible one. We deemed that it would be
+better to support this interoperability. The change also means that Unicode
+strings are now stored as UTF-8 rather than pickled, which may or may not
+result in a slight performance improvement for this type of data.
+
+We have also introduced a `pickle_protocol` behavior to enable seamless
+interoperability between Python 2.x and 3.x. Also, this release introduces a
+ManyLinux wheel, making installation a breeze on ManyLinux systems (which I
+suppose is many linuxes.)
+
New in version 1.5.0
--------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/docs/conf.py
new/pylibmc-1.6.1/docs/conf.py
--- old/pylibmc-1.5.2/docs/conf.py 2015-10-10 22:09:43.000000000 +0200
+++ new/pylibmc-1.6.1/docs/conf.py 2018-11-09 19:35:16.000000000 +0100
@@ -24,7 +24,7 @@
else:
sys.path.insert(0, pylibmc_dir)
-import pylibmc
+import _pylibmc
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -53,18 +53,21 @@
master_doc = 'index'
# General information about the project.
-project = pylibmc.__name__
-copyright = u'2011, Ludvig Ericson'
+project = 'pylibmc'
+copyright = u'2018, Ludvig Ericson'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = pylibmc.__version__
+version = _pylibmc.__version__
# The full version, including alpha/beta/rc tags.
release = version
+print(_pylibmc.__file__)
+print(project, release)
+
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/docs/install.rst
new/pylibmc-1.6.1/docs/install.rst
--- old/pylibmc-1.5.2/docs/install.rst 2016-06-13 16:18:53.000000000 +0200
+++ new/pylibmc-1.6.1/docs/install.rst 2019-08-15 13:49:27.000000000 +0200
@@ -5,8 +5,8 @@
Requirements
============
-* Python 2.5, Python 3.2 or later
-* libmemcached 0.32 or later (last test with 1.0.18)
+* Python 2.6-2.7, or Python 3.3-3.7
+* libmemcached 1.0.8 or later (latest tested is 1.0.18)
* zlib (required for compression support)
* libsasl2 (required for authentication support)
@@ -28,7 +28,11 @@
From PyPI
---------
-Since ``pip`` doesn't support passing arguments to the setup script,
-you can also define environment variables::
+Using ``pip`` you can pass install options as follows::
- LIBMEMCACHED=/opt/local pip install pylibmc
+ pip install pylibmc --install-option="--with-libmemcached=/usr/local/"
+
+Using Homebrew (MacOSX) you can install from PyPI via::
+
+ brew install libmemcached
+ pip install pylibmc
--install-option="--with-libmemcached=/usr/local/Cellar/libmemcached"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/docs/reference.rst
new/pylibmc-1.6.1/docs/reference.rst
--- old/pylibmc-1.5.2/docs/reference.rst 2016-08-09 18:06:26.000000000
+0200
+++ new/pylibmc-1.6.1/docs/reference.rst 2018-11-09 18:42:08.000000000
+0100
@@ -180,13 +180,13 @@
.. method:: touch(key, time) -> touched
- Touch a given *key* and increase it's expiry time by *time* seconds.
+ Touch a given *key* and set its expiry time to *time* seconds.
:param key: Key to touch
:param time: Number of seconds until the key expires.
Returns ``True`` if the key was successfully touched. ``False``
- if the key did not exist.
+ if the key did not exist (so touching is not possible.)
.. Utilities
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/setup.py new/pylibmc-1.6.1/setup.py
--- old/pylibmc-1.5.2/setup.py 2016-08-09 18:06:26.000000000 +0200
+++ new/pylibmc-1.6.1/setup.py 2019-08-15 13:49:27.000000000 +0200
@@ -76,14 +76,14 @@
# strict aliasing rules. Let's skip this flag for now.
cflags = ["-fno-strict-aliasing", "-std=c99"]
-## Extension definitions
+# Extension definitions
pylibmc_ext = Extension("_pylibmc", ["src/_pylibmcmodule.c"],
libraries=libs, include_dirs=incdirs,
library_dirs=libdirs, define_macros=defs,
extra_compile_args=cflags)
-# Hidden secret: if environment variable GEN_SETUP is set, generate Setup file.
+# Hidden secret: generate Setup file for statically compiling the extension.
if cmd == "gen-setup":
line = " ".join((
pylibmc_ext.name,
@@ -122,5 +122,7 @@
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
],
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/src/_pylibmcmodule.c
new/pylibmc-1.6.1/src/_pylibmcmodule.c
--- old/pylibmc-1.5.2/src/_pylibmcmodule.c 2017-02-25 17:39:03.000000000
+0100
+++ new/pylibmc-1.6.1/src/_pylibmcmodule.c 2019-08-15 14:01:27.000000000
+0200
@@ -148,6 +148,8 @@
PyObject *behaviors = NULL;
memcached_return rc;
+ self->pickle_protocol = -1;
+
static char *kws[] = { "servers", "binary", "username", "password",
"behaviors", NULL };
@@ -352,9 +354,8 @@
goto error;
}
- if(strm.total_out >= value_len) {
- /* if we didn't actually save anything, don't bother storing it
- compressed */
+ if ((Py_ssize_t)strm.total_out >= value_len) {
+ /* if no data was saved, don't use compression */
goto error;
}
@@ -594,7 +595,7 @@
#else
if (flags & PYLIBMC_FLAG_ZLIB) {
PyErr_SetString(PylibMCExc_Error,
- "value for key compressed, unable to inflate");
+ "key is compressed but pylibmc is compiled without zlib support");
return NULL;
}
#endif
@@ -645,20 +646,21 @@
switch (dtype) {
case PYLIBMC_FLAG_PICKLE:
- retval = value ? _PylibMC_Unpickle_Bytes(value) :
_PylibMC_Unpickle(value_str, value_size);
+ retval = value ? _PylibMC_Unpickle_Bytes(self, value) :
_PylibMC_Unpickle(self, value_str, value_size);
break;
case PYLIBMC_FLAG_INTEGER:
case PYLIBMC_FLAG_LONG:
- case PYLIBMC_FLAG_BOOL:
if (value) {
retval = PyLong_FromString(PyBytes_AS_STRING(value), NULL, 10);
} else {
retval = _PyLong_FromStringAndSize(value_str, value_size,
NULL, 10);;
}
- if (retval != NULL && dtype == PYLIBMC_FLAG_BOOL) {
- PyObject *bool_retval =
PyBool_FromLong(PyLong_AS_LONG(retval));
- Py_DECREF(retval);
- retval = bool_retval;
+ break;
+ case PYLIBMC_FLAG_TEXT:
+ if (value) {
+ retval = PyUnicode_FromEncodedObject(value, "utf-8", "strict");
+ } else {
+ retval = PyUnicode_FromStringAndSize(value_str, value_size);
}
break;
case PYLIBMC_FLAG_NONE:
@@ -723,7 +725,7 @@
if (!_key_normalized_obj(&key)) {
return NULL;
- } else if (!PySequence_Length(key) ) {
+ } else if (!PySequence_Length(key)) {
Py_INCREF(default_value);
return default_value;
}
@@ -736,18 +738,23 @@
Py_DECREF(key);
- if (mc_val != NULL) {
+ if (error == MEMCACHED_SUCCESS) {
+ /* note that mc_val can and is NULL for zero-length values. */
PyObject *r = _PylibMC_parse_memcached_value(self, mc_val, val_size,
flags);
- free(mc_val);
+
+ if (mc_val != NULL) {
+ free(mc_val);
+ }
+
if (_PylibMC_cache_miss_simulated(r)) {
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) {
+ }
+
+ if (error == MEMCACHED_NOTFOUND) {
Py_INCREF(default_value);
return default_value;
}
@@ -1247,12 +1254,12 @@
/* Make store_val an owned reference */
store_val = value_obj;
Py_INCREF(store_val);
+ } else if (PyUnicode_Check(value_obj)) {
+ store_flags = PYLIBMC_FLAG_TEXT;
+ store_val = PyUnicode_AsUTF8String(value_obj);
} else if (PyBool_Check(value_obj)) {
- store_flags |= PYLIBMC_FLAG_BOOL;
- /* bool cannot be subclassed; there are only two singleton values,
- Py_True and Py_False */
- const char *value_str = (value_obj == Py_True) ? "1" : "0";
- store_val = PyBytes_FromString(value_str);
+ store_flags |= PYLIBMC_FLAG_INTEGER;
+ store_val = PyBytes_FromStringAndSize(&"01"[value_obj == Py_True], 1);
#if PY_MAJOR_VERSION >= 3
} else if (PyLong_Check(value_obj)) {
store_flags |= PYLIBMC_FLAG_LONG;
@@ -1275,7 +1282,7 @@
/* we have no idea what it is, so we'll store it pickled */
Py_INCREF(value_obj);
store_flags |= PYLIBMC_FLAG_PICKLE;
- store_val = _PylibMC_Pickle(value_obj);
+ store_val = _PylibMC_Pickle(self, value_obj);
Py_DECREF(value_obj);
}
@@ -2128,14 +2135,21 @@
uint64_t bval;
PyObject *x;
- bval = memcached_behavior_get(self->mc, b->flag);
+ switch (b->flag) {
+ case PYLIBMC_BEHAVIOR_PICKLE_PROTOCOL:
+ bval = self->pickle_protocol;
+ break;
+ default:
+ bval = memcached_behavior_get(self->mc, b->flag);
+ }
+
x = PyLong_FromLong((long)bval);
if (x == NULL || PyDict_SetItemString(retval, b->name, x) == -1) {
Py_XDECREF(x);
goto error;
}
-
Py_DECREF(x);
+
}
return retval;
@@ -2148,7 +2162,7 @@
PyObject *behaviors) {
PylibMC_Behavior *b;
PyObject *py_v;
- uint64_t v;
+ long v;
memcached_return r;
char *key;
@@ -2163,16 +2177,23 @@
goto error;
}
- v = (uint64_t)PyLong_AS_LONG(py_v);
+ v = PyLong_AsLong(py_v);
Py_DECREF(py_v);
- r = memcached_behavior_set(self->mc, b->flag, v);
- if (r != MEMCACHED_SUCCESS) {
- PyErr_Format(PylibMCExc_Error,
- "memcached_behavior_set returned %d for "
- "behavior '%.32s' = %u", r, b->name, (unsigned int)v);
- goto error;
+ switch (b->flag) {
+ case PYLIBMC_BEHAVIOR_PICKLE_PROTOCOL:
+ self->pickle_protocol = v;
+ break;
+ default:
+ r = memcached_behavior_set(self->mc, b->flag, (uint64_t)v);
+ if (r != MEMCACHED_SUCCESS) {
+ PyErr_Format(PylibMCExc_Error,
+ "memcached_behavior_set returned %d for "
+ "behavior '%.32s' = %ld", r, b->name, v);
+ goto error;
+ }
}
+
}
for (b = PylibMC_callbacks; b->name != NULL; b++) {
@@ -2383,6 +2404,7 @@
Py_END_ALLOW_THREADS;
clone->native_serialization = self->native_serialization;
clone->native_deserialization = self->native_deserialization;
+ clone->pickle_protocol = self->pickle_protocol;
return (PyObject *)clone;
}
/* }}} */
@@ -2471,7 +2493,7 @@
return pickle_attr;
}
-static PyObject *_PylibMC_Unpickle(const char *buff, Py_ssize_t size) {
+static PyObject *_PylibMC_Unpickle(PylibMC_Client *self, const char *buff,
Py_ssize_t size) {
#if PY_MAJOR_VERSION >= 3
return PyObject_CallFunction(_PylibMC_pickle_loads, "y#", buff, size);
#else
@@ -2479,12 +2501,12 @@
#endif
}
-static PyObject *_PylibMC_Unpickle_Bytes(PyObject *val) {
+static PyObject *_PylibMC_Unpickle_Bytes(PylibMC_Client *self, PyObject *val) {
return PyObject_CallFunctionObjArgs(_PylibMC_pickle_loads, val, NULL);
}
-static PyObject *_PylibMC_Pickle(PyObject *val) {
- return PyObject_CallFunction(_PylibMC_pickle_dumps, "Oi", val, -1);
+static PyObject *_PylibMC_Pickle(PylibMC_Client *self, PyObject *val) {
+ return PyObject_CallFunction(_PylibMC_pickle_dumps, "Oi", val,
self->pickle_protocol);
}
/* }}} */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/src/_pylibmcmodule.h
new/pylibmc-1.6.1/src/_pylibmcmodule.h
--- old/pylibmc-1.5.2/src/_pylibmcmodule.h 2016-08-09 18:06:26.000000000
+0200
+++ new/pylibmc-1.6.1/src/_pylibmcmodule.h 2018-11-09 18:42:08.000000000
+0100
@@ -60,23 +60,29 @@
/* {{{ Key flags from python-memcached
* Some flags (like the compression one, ZLIB) are combined with others.
*/
-#define PYLIBMC_FLAG_NONE 0
-#define PYLIBMC_FLAG_PICKLE (1 << 0)
-#define PYLIBMC_FLAG_INTEGER (1 << 1)
-#define PYLIBMC_FLAG_LONG (1 << 2)
-/* Note: this is an addition! python-memcached doesn't handle bools. */
-#define PYLIBMC_FLAG_BOOL (1 << 4)
-#define PYLIBMC_FLAG_TYPES (PYLIBMC_FLAG_PICKLE | PYLIBMC_FLAG_INTEGER | \
- PYLIBMC_FLAG_LONG | PYLIBMC_FLAG_BOOL)
-/* Modifier flags */
-#define PYLIBMC_FLAG_ZLIB (1 << 3)
+enum PylibMC_Flags {
+ PYLIBMC_FLAG_NONE = 0,
+ PYLIBMC_FLAG_PICKLE = (1 << 0),
+ PYLIBMC_FLAG_INTEGER = (1 << 1),
+ PYLIBMC_FLAG_LONG = (1 << 2),
+ PYLIBMC_FLAG_ZLIB = (1 << 3),
+ PYLIBMC_FLAG_TEXT = (1 << 4),
+};
+
+#define PYLIBMC_FLAG_TYPES (PYLIBMC_FLAG_PICKLE | PYLIBMC_FLAG_INTEGER | \
+ PYLIBMC_FLAG_LONG | PYLIBMC_FLAG_TEXT)
+/* }}} */
+
+/* Behaviors that only affects pylibmc (i.e. not memached_set_behavior etc) */
+enum PylibMC_Behaviors {
+ PYLIBMC_BEHAVIOR_PICKLE_PROTOCOL = 0xcafe0000,
+};
/* Python 3 stuff */
#ifndef PyVarObject_HEAD_INIT
#define PyVarObject_HEAD_INIT(type, size) \
PyObject_HEAD_INIT(type) size,
#endif
-/* }}} */
typedef memcached_return (*_PylibMC_SetCommand)(memcached_st *, const char *,
size_t, const char *, size_t, time_t, uint32_t);
@@ -228,6 +234,7 @@
#if LIBMEMCACHED_VERSION_HEX >= 0x01000003
{ MEMCACHED_BEHAVIOR_DEAD_TIMEOUT, "dead_timeout" },
#endif
+ { PYLIBMC_BEHAVIOR_PICKLE_PROTOCOL, "pickle_protocol" },
{ 0, NULL }
};
@@ -278,6 +285,7 @@
uint8_t sasl_set;
uint8_t native_serialization;
uint8_t native_deserialization;
+ int pickle_protocol;
} PylibMC_Client;
/* {{{ Prototypes */
@@ -315,9 +323,9 @@
memcached_return, const char *, Py_ssize_t);
static PyObject *PylibMC_ErrFromMemcached(PylibMC_Client *, const char *,
memcached_return);
-static PyObject *_PylibMC_Unpickle(const char *, Py_ssize_t);
-static PyObject *_PylibMC_Unpickle_Bytes(PyObject *);
-static PyObject *_PylibMC_Pickle(PyObject *);
+static PyObject *_PylibMC_Unpickle(PylibMC_Client *, const char *, Py_ssize_t);
+static PyObject *_PylibMC_Unpickle_Bytes(PylibMC_Client *, PyObject *);
+static PyObject *_PylibMC_Pickle(PylibMC_Client *, 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 *);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/src/pylibmc/__main__.py
new/pylibmc-1.6.1/src/pylibmc/__main__.py
--- old/pylibmc-1.5.2/src/pylibmc/__main__.py 2015-06-17 13:21:50.000000000
+0200
+++ new/pylibmc-1.6.1/src/pylibmc/__main__.py 2018-11-09 18:42:08.000000000
+0100
@@ -20,14 +20,14 @@
def collect_servers():
try:
in_addr = raw_input("Address [127.0.0.1]: ")
- except:
+ except NameError:
in_addr = input("Address [127.0.0.1]: ")
if in_addr:
while in_addr:
yield in_addr
try:
in_addr = raw_input("Address [<stop>]: ")
- except:
+ except NameError:
in_addr = input("Address [<stop>]: ")
else:
yield "127.0.0.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/src/pylibmc/autoconf.py
new/pylibmc-1.6.1/src/pylibmc/autoconf.py
--- old/pylibmc-1.5.2/src/pylibmc/autoconf.py 1970-01-01 01:00:00.000000000
+0100
+++ new/pylibmc-1.6.1/src/pylibmc/autoconf.py 2018-11-09 18:42:08.000000000
+0100
@@ -0,0 +1,62 @@
+"Autoconfiguration"
+
+from __future__ import unicode_literals
+import pylibmc
+
+class UnsupportedAutoconfMethod(Exception):
+ pass
+
+class NoAutoconfFound(Exception):
+ pass
+
+def _elasticache_config_get(address, key):
+ import socket
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+ host, port = address.split(':')
+ port = int(port)
+ sock.connect((host, port))
+ sock.send(('config get %s\r\n' % (key,)).encode('ascii'))
+ state = 'wait-nl-header'
+ nbytes = 0
+ buff = b''
+ while True:
+ chunk = sock.recv(4096)
+ if not chunk:
+ raise RuntimeError('failed reading cluster config')
+ buff += chunk
+ if state.startswith('wait-nl-') and b'\r\n' not in buff:
+ continue
+ elif state == 'wait-nl-header':
+ line, buff = buff.split(b'\r\n', 1)
+ if line.lower() == b'error':
+ raise UnsupportedAutoconfMethod()
+ cmd, key, flags, nbytes = line.split()
+ flags, nbytes = int(flags), int(nbytes)
+ state = 'read-body'
+ elif state == 'ready-body':
+ if len(buff) < nbytes:
+ continue
+ config, buff = buff[:nbytes], buff[nbytes+2:]
+ state = 'wait-nl-end'
+ elif state == 'wait-nl-end':
+ break
+ else:
+ raise RuntimeError(state)
+ return config
+
+def _parse_elasticache_config(cfg):
+ ver, nodes = cfg.split(b'\n')
+ ver, nodes = int(ver), [n.decode('ascii').split('|') for n in
nodes.split()]
+ # NOTE Should probably verify ver == 12, but why not try anyways
+ return ['%s:%s' % (addr or cname, port) for (cname, addr, port) in nodes]
+
+def elasticache(address='127.0.0.1:11211', config_key=b'cluster',
+ mc_key='AmazonElastiCache:cluster'):
+ try:
+ config = _elasticache_config_get(address, config_key)
+ except UnsupportedAutoconfMethod:
+ config = pylibmc.Client([address]).get(mc_key)
+ if config is None:
+ raise NoAutoconfFound
+ hosts = _parse_elasticache_config(config)
+ return pylibmc.Client(hosts)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/src/pylibmc-version.h
new/pylibmc-1.6.1/src/pylibmc-version.h
--- old/pylibmc-1.5.2/src/pylibmc-version.h 2017-03-06 14:10:05.000000000
+0100
+++ new/pylibmc-1.6.1/src/pylibmc-version.h 2019-08-15 14:03:49.000000000
+0200
@@ -1 +1 @@
-#define PYLIBMC_VERSION "1.5.2"
+#define PYLIBMC_VERSION "1.6.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/tests/__init__.py
new/pylibmc-1.6.1/tests/__init__.py
--- old/pylibmc-1.5.2/tests/__init__.py 2016-02-25 17:51:25.000000000 +0100
+++ new/pylibmc-1.6.1/tests/__init__.py 2019-08-15 13:49:27.000000000 +0200
@@ -23,14 +23,6 @@
self.mc.disconnect_all()
del self.mc
-def dump_infos():
- if hasattr(_pylibmc, "__file__"):
- print("Starting tests with _pylibmc at", _pylibmc.__file__)
- else:
- print("Starting tests with static _pylibmc:", _pylibmc)
- print("Reported libmemcached version:", _pylibmc.libmemcached_version)
- print("Reported pylibmc version:", _pylibmc.__version__)
- print("Support compression:", _pylibmc.support_compression)
def get_refcounts(refcountables):
"""Measure reference counts during testing.
@@ -39,5 +31,6 @@
one new reference is created as the argument to sys.getrefcount).
Therefore, try to do it in a consistent and deterministic fashion.
"""
- gc.collect()
- return [sys.getrefcount(val) for val in refcountables]
+ if hasattr(sys, 'getrefcount'):
+ gc.collect()
+ return [sys.getrefcount(val) for val in refcountables]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/tests/test_autoconf.py
new/pylibmc-1.6.1/tests/test_autoconf.py
--- old/pylibmc-1.5.2/tests/test_autoconf.py 1970-01-01 01:00:00.000000000
+0100
+++ new/pylibmc-1.6.1/tests/test_autoconf.py 2018-11-09 18:42:08.000000000
+0100
@@ -0,0 +1,21 @@
+from pylibmc import autoconf
+from tests import PylibmcTestCase
+
+class AutoConfTests(PylibmcTestCase):
+ def test_no_autoconf(self):
+ self.mc.delete('AmazonElastiCache:cluster')
+ self.assertRaises(autoconf.NoAutoconfFound, autoconf.elasticache)
+
+ def test_autoconf(self):
+ addrtup = (self.memcached_host, self.memcached_port)
+ self.mc.set('AmazonElastiCache:cluster', ('12\nlocalhost|%s|%s' %
addrtup).encode('ascii'))
+ mc = autoconf.elasticache(address=('%s:%s' % addrtup))
+ self.assert_(mc.set('a', 'b'))
+ self.assertEqual(mc.get('a'), 'b')
+
+ def test_autoconf_only_cname(self):
+ addrtup = (self.memcached_host, self.memcached_port)
+ self.mc.set('AmazonElastiCache:cluster', ('12\n%s||%s' %
addrtup).encode('ascii'))
+ mc = autoconf.elasticache(address=('%s:%s' % addrtup))
+ self.assert_(mc.set('a', 'b'))
+ self.assertEqual(mc.get('a'), 'b')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/tests/test_client.py
new/pylibmc-1.6.1/tests/test_client.py
--- old/pylibmc-1.5.2/tests/test_client.py 2016-08-09 18:06:26.000000000
+0200
+++ new/pylibmc-1.6.1/tests/test_client.py 2018-11-09 18:42:08.000000000
+0100
@@ -43,9 +43,9 @@
expected_behaviors = [
'auto_eject', 'buffer_requests', 'cas', 'connect_timeout',
'distribution', 'failure_limit', 'hash', 'ketama', 'ketama_hash',
- 'ketama_weighted', 'no_block', 'num_replicas', 'receive_timeout',
- 'retry_timeout', 'send_timeout', 'tcp_keepalive', 'tcp_nodelay',
- 'verify_keys']
+ 'ketama_weighted', 'no_block', 'num_replicas', 'pickle_protocol',
+ 'receive_timeout', 'retry_timeout', 'send_timeout',
+ 'tcp_keepalive', 'tcp_nodelay', 'verify_keys']
# Since some parts of pyblibmc's functionality depend on the
# libmemcached version, programatically check for the expected values
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/tests/test_refcounts.py
new/pylibmc-1.6.1/tests/test_refcounts.py
--- old/pylibmc-1.5.2/tests/test_refcounts.py 2016-08-09 18:06:26.000000000
+0200
+++ new/pylibmc-1.6.1/tests/test_refcounts.py 2019-08-15 13:49:27.000000000
+0200
@@ -2,7 +2,6 @@
from __future__ import print_function
import datetime
-import sys
from nose.tools import eq_, ok_
@@ -170,14 +169,14 @@
def test_get_invalid_key(self):
bc = make_test_client(binary=True)
key = object()
- initial_refcount = sys.getrefcount(key)
+ initial_refcount = get_refcounts([key])
raised = False
try:
bc.get(key)
except TypeError:
raised = True
assert raised
- eq_(sys.getrefcount(key), initial_refcount)
+ eq_(get_refcounts([key]), initial_refcount)
def test_cas(self):
k = "testkey"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pylibmc-1.5.2/tests/test_serialization.py
new/pylibmc-1.6.1/tests/test_serialization.py
--- old/pylibmc-1.5.2/tests/test_serialization.py 2016-08-18
15:30:00.000000000 +0200
+++ new/pylibmc-1.6.1/tests/test_serialization.py 2018-11-09
18:42:08.000000000 +0100
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
from __future__ import unicode_literals
from __future__ import print_function
@@ -25,6 +27,8 @@
# this happens under Python 3
return val
+f_none = 0
+f_pickle, f_int, f_long, f_zlib, f_text = (1 << i for i in range(5))
class SerializationMethodTests(PylibmcTestCase):
"""Coverage tests for serialize and deserialize."""
@@ -32,29 +36,33 @@
def test_integers(self):
c = make_test_client(binary=True)
if sys.version_info[0] == 3:
- eq_(c.serialize(1), (b'1', 4))
- eq_(c.serialize(2**64), (b'18446744073709551616', 4))
+ eq_(c.serialize(1), (b'1', f_long))
+ eq_(c.serialize(2**64), (b'18446744073709551616', f_long))
else:
- eq_(c.serialize(1), (b'1', 2))
- eq_(c.serialize(2**64), (b'18446744073709551616', 4))
+ eq_(c.serialize(1), (b'1', f_int))
+ eq_(c.serialize(2**64), (b'18446744073709551616', f_long))
- eq_(c.deserialize(b'1', 2), 1)
+ eq_(c.deserialize(b'1', f_int), 1)
- eq_(c.deserialize(b'18446744073709551616', 4), 2**64)
- eq_(c.deserialize(b'1', 4), long_(1))
+ eq_(c.deserialize(b'18446744073709551616', f_long), 2**64)
+ eq_(c.deserialize(b'1', f_long), long_(1))
def test_nonintegers(self):
# tuples (python_value, (expected_bytestring, expected_flags))
SERIALIZATION_TEST_VALUES = [
- # booleans
- (True, (b'1', 16)),
- (False, (b'0', 16)),
+ # booleans are just ints
+ (True, (b'1', f_int)),
+ (False, (b'0', f_int)),
# bytestrings
- (b'asdf', (b'asdf', 0)),
- (b'\xb5\xb1\xbf\xed\xa9\xc2{8', (b'\xb5\xb1\xbf\xed\xa9\xc2{8',
0)),
+ (b'asdf', (b'asdf', f_none)),
+ (b'\xb5\xb1\xbf\xed\xa9\xc2{8', (b'\xb5\xb1\xbf\xed\xa9\xc2{8',
f_none)),
+ (b'', (b'', f_none)),
+ # unicode objects
+ (u'åäö', (u'åäö'.encode('utf-8'), f_text)),
+ (u'', (b'', f_text)),
# objects
(datetime.date(2015, 12, 28), (pickle.dumps(datetime.date(2015,
12, 28),
- protocol=-1), 1)),
+ protocol=-1),
f_pickle)),
]
c = make_test_client(binary=True)