Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pylibmc for openSUSE:Factory checked in at 2022-11-24 12:22:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pylibmc (Old) and /work/SRC/openSUSE:Factory/.python-pylibmc.new.1597 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pylibmc" Thu Nov 24 12:22:12 2022 rev:10 rq:1037468 version:1.6.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pylibmc/python-pylibmc.changes 2021-12-12 21:27:19.480331419 +0100 +++ /work/SRC/openSUSE:Factory/.python-pylibmc.new.1597/python-pylibmc.changes 2022-11-24 12:22:16.076931023 +0100 @@ -1,0 +2,16 @@ +Tue Nov 22 15:19:48 UTC 2022 - Markéta Machová <mmach...@suse.com> + +- Update to 1.6.3 + * Fix logger.warn() deprecation warnings + * Modernize tests and test harness + * Python 3.10 support +- Remove python-pylibmc-remove-nose.patch + +------------------------------------------------------------------- +Fri Nov 18 14:59:02 UTC 2022 - Dominique Leuenberger <dims...@opensuse.org> + +- Cope with memcached moving from sbindir to bindir and safeguard + against non-existing memcached binary: it if can't be started, + there is no reason to even attempt to run the test suite. + +------------------------------------------------------------------- Old: ---- pylibmc-1.6.1.tar.gz python-pylibmc-remove-nose.patch New: ---- pylibmc-1.6.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pylibmc.spec ++++++ --- /var/tmp/diff_new_pack.7ZYlyH/_old 2022-11-24 12:22:16.704935015 +0100 +++ /var/tmp/diff_new_pack.7ZYlyH/_new 2022-11-24 12:22:16.708935040 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-pylibmc # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,17 +16,14 @@ # -%{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-pylibmc -Version: 1.6.1 +Version: 1.6.3 Release: 0 Summary: memcached client for Python License: BSD-3-Clause Group: Development/Languages/Python URL: https://github.com/lericson/pylibmc Source: https://files.pythonhosted.org/packages/source/p/pylibmc/pylibmc-%{version}.tar.gz -# https://github.com/lericson/pylibmc/pull/263 -Patch0: python-pylibmc-remove-nose.patch BuildRequires: %{python_module devel} BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} @@ -47,7 +44,6 @@ %prep %setup -q -n pylibmc-%{version} -%patch0 -p1 %build export CFLAGS="%{optflags}" @@ -58,14 +54,23 @@ %python_expand %fdupes %{buildroot}%{$python_sitearch} %check -%{_sbindir}/memcached & +if [ -f %{_sbindir}/memcached ]; then + %{_sbindir}/memcached & +elif [ -f %{_bindir}/memcached ]; then + %{_bindir}/memcached & +else + echo "Failed to start memcached - tests can't pass" + exit 1 +fi pid=$! -%pytest_arch -k 'not testBigGetMulti' +%pytest_arch kill $pid %files %{python_files} %license LICENSE %doc README.rst -%{python_sitearch}/* +%{python_sitearch}/pylibmc +%{python_sitearch}/_pylibmc*.so +%{python_sitearch}/pylibmc-%{version}*-info %changelog ++++++ pylibmc-1.6.1.tar.gz -> pylibmc-1.6.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/PKG-INFO new/pylibmc-1.6.3/PKG-INFO --- old/pylibmc-1.6.1/PKG-INFO 2019-08-15 14:04:10.000000000 +0200 +++ new/pylibmc-1.6.3/PKG-INFO 2022-08-26 10:56:23.000000000 +0200 @@ -1,19 +1,19 @@ Metadata-Version: 1.1 Name: pylibmc -Version: 1.6.1 +Version: 1.6.3 Summary: Quick and small memcached client for Python -Home-page: http://sendapatch.se/projects/pylibmc/ +Home-page: https://sendapatch.se/projects/pylibmc/ Author: Ludvig Ericson Author-email: lud...@lericson.se -License: 3-clause BSD <http://www.opensource.org/licenses/bsd-license.php> +License: 3-clause BSD <https://opensource.org/licenses/bsd-license.php> Description: `pylibmc` is a Python client for `memcached <http://memcached.org/>`_ written in C. See `the documentation at sendapatch.se/projects/pylibmc/`__ for more information. __ http://sendapatch.se/projects/pylibmc/ - .. image:: https://travis-ci.org/lericson/pylibmc.png?branch=master - :target: https://travis-ci.org/lericson/pylibmc + .. image:: https://github.com/lericson/pylibmc/actions/workflows/ci.yml/badge.svg + :target: https://github.com/lericson/pylibmc/actions/workflows/ci.yml New in version 1.6.0 ==================== @@ -88,13 +88,10 @@ Platform: UNKNOWN Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 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 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3 :: Only diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/README.rst new/pylibmc-1.6.3/README.rst --- old/pylibmc-1.6.1/README.rst 2018-11-09 18:49:56.000000000 +0100 +++ new/pylibmc-1.6.3/README.rst 2022-08-26 10:56:22.000000000 +0200 @@ -4,8 +4,8 @@ __ http://sendapatch.se/projects/pylibmc/ -.. image:: https://travis-ci.org/lericson/pylibmc.png?branch=master - :target: https://travis-ci.org/lericson/pylibmc +.. image:: https://github.com/lericson/pylibmc/actions/workflows/ci.yml/badge.svg + :target: https://github.com/lericson/pylibmc/actions/workflows/ci.yml New in version 1.6.0 ==================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/docs/behaviors.rst new/pylibmc-1.6.3/docs/behaviors.rst --- old/pylibmc-1.6.1/docs/behaviors.rst 2018-11-09 18:42:08.000000000 +0100 +++ new/pylibmc-1.6.3/docs/behaviors.rst 2022-08-26 10:56:22.000000000 +0200 @@ -220,7 +220,7 @@ support: if a server goes down, just use another one. This case is supported, but not by default. As explained above, the default distribution mechanism is not very smart, and libmemcached doesn't support any meaningful failover for -it. If a server goes down, it stays down, and all of its alloted keys will +it. If a server goes down, it stays down, and all of its allotted keys will simply fail. The recommended failover behaviors is for that reason:: mc.behaviors['ketama'] = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/docs/conf.py new/pylibmc-1.6.3/docs/conf.py --- old/pylibmc-1.6.1/docs/conf.py 2018-11-09 19:35:16.000000000 +0100 +++ new/pylibmc-1.6.3/docs/conf.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # pylibmc documentation build configuration file, created by # sphinx-quickstart on Mon Jun 13 13:53:22 2011. @@ -18,9 +17,9 @@ if not pylibmc_dir: raise RuntimeError("please set PYLIBMC_DIR") elif not os.path.exists(pylibmc_dir): - raise RuntimeError("PYLIBMC_DIR %r does not exist" % (pylibmc_dir,)) + raise RuntimeError(f"PYLIBMC_DIR {pylibmc_dir!r} does not exist") elif not os.path.isdir(pylibmc_dir): - raise RuntimeError("PYLIBMC_DIR %r is not a directory" % (pylibmc_dir,)) + raise RuntimeError(f"PYLIBMC_DIR {pylibmc_dir!r} is not a directory") else: sys.path.insert(0, pylibmc_dir) @@ -54,7 +53,7 @@ # General information about the project. project = 'pylibmc' -copyright = u'2018, Ludvig Ericson' +copyright = '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 @@ -194,8 +193,8 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'pylibmc.tex', u'pylibmc Documentation', - u'Ludvig Ericson', 'manual'), + ('index', 'pylibmc.tex', 'pylibmc Documentation', + 'Ludvig Ericson', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -227,6 +226,6 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'pylibmc', u'pylibmc Documentation', - [u'Ludvig Ericson'], 1) + ('index', 'pylibmc', 'pylibmc Documentation', + ['Ludvig Ericson'], 1) ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/docs/install.rst new/pylibmc-1.6.3/docs/install.rst --- old/pylibmc-1.6.1/docs/install.rst 2019-08-15 13:49:27.000000000 +0200 +++ new/pylibmc-1.6.3/docs/install.rst 2022-08-26 10:56:22.000000000 +0200 @@ -5,7 +5,7 @@ Requirements ============ -* Python 2.6-2.7, or Python 3.3-3.7 +* Python 3.6+ * libmemcached 1.0.8 or later (latest tested is 1.0.18) * zlib (required for compression support) * libsasl2 (required for authentication support) @@ -25,14 +25,15 @@ libmemcached would end up in ``/opt/local``, hence ``--with-libmemcached=/opt/local``. -From PyPI ---------- +Using ``pip`` you achieve the same thing as follows:: -Using ``pip`` you can pass install options as follows:: + pip install pylibmc --install-option="--with-libmemcached=/opt/local" - pip install pylibmc --install-option="--with-libmemcached=/usr/local/" +Note that `/usr/local` is typically on the library search path. If it is not, +you'd probably want to fix that instead. -Using Homebrew (MacOSX) you can install from PyPI via:: +Homebrew and MacOS +------------------ brew install libmemcached - pip install pylibmc --install-option="--with-libmemcached=/usr/local/Cellar/libmemcached" + pip install pylibmc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/setup.py new/pylibmc-1.6.3/setup.py --- old/pylibmc-1.6.1/setup.py 2019-08-15 13:49:27.000000000 +0200 +++ new/pylibmc-1.6.3/setup.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,12 +1,7 @@ -from __future__ import print_function import os import sys from distutils.core import setup, Extension -# Need an 'open' function that supports the 'encoding' argument: -if sys.version_info[0] < 3: - from codecs import open - ## Command-line argument parsing # --with-zlib: use zlib for compressing and decompressing @@ -22,11 +17,13 @@ incdirs = [] libdirs = [] + def append_env(L, e): v = os.environ.get(e) if v and os.path.exists(v): L.append(v) + append_env(pkgdirs, "LIBMEMCACHED") append_env(pkgdirs, "ZLIB") @@ -95,34 +92,35 @@ s.write(line + "\n") sys.exit(0) -with open("README.rst", "U", encoding="utf-8") as r: +with open("README.rst", encoding="utf-8") as r: readme_text = r.read() -with open("src/pylibmc-version.h", "U", encoding="utf-8") as r: +with open("src/pylibmc-version.h", encoding="utf-8") as r: version = r.read().strip().split("\"")[1] setup( name="pylibmc", version=version, - url="http://sendapatch.se/projects/pylibmc/", + url="https://sendapatch.se/projects/pylibmc/", + project_urls={ + "Source": "https://github.com/lericson/pylibmc", + }, author="Ludvig Ericson", author_email="lud...@lericson.se", - license="3-clause BSD <http://www.opensource.org/licenses/bsd-license.php>", + license="3-clause BSD <https://opensource.org/licenses/bsd-license.php>", description="Quick and small memcached client for Python", long_description=readme_text, ext_modules=[pylibmc_ext], package_dir={'': 'src'}, packages=['pylibmc'], + python_requires='>=3.6', classifiers=[ 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', - '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', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3 :: Only', ], ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/src/_pylibmcmodule.c new/pylibmc-1.6.3/src/_pylibmcmodule.c --- old/pylibmc-1.6.1/src/_pylibmcmodule.c 2019-08-15 14:01:27.000000000 +0200 +++ new/pylibmc-1.6.3/src/_pylibmcmodule.c 2022-08-26 10:56:22.000000000 +0200 @@ -55,7 +55,6 @@ #define PyInt_Check PyLong_Check #endif -#if PY_MAJOR_VERSION >= 3 #define MOD_ERROR_VAL NULL #define MOD_SUCCESS_VAL(val) val #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) @@ -63,25 +62,6 @@ static struct PyModuleDef moduledef = { \ PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \ ob = PyModule_Create(&moduledef); -#else -#define MOD_ERROR_VAL -#define MOD_SUCCESS_VAL(val) -#define MOD_INIT(name) void init##name(void) -#define MOD_DEF(ob, name, doc, methods) \ - ob = Py_InitModule3(name, methods, doc); -#define PyBytes_AS_STRING PyString_AS_STRING -#define PyBytes_AsStringAndSize PyString_AsStringAndSize -#define PyBytes_Check PyString_Check -#define PyBytes_Concat PyString_Concat -#define PyBytes_FromFormat PyString_FromFormat -#define PyBytes_FromString PyString_FromString -#define PyBytes_FromStringAndSize PyString_FromStringAndSize -#define PyBytes_GET_SIZE PyString_GET_SIZE -#define PyBytes_Size PyString_Size -#define PyLong_AS_LONG PyInt_AS_LONG -#define _PyBytes_Resize _PyString_Resize -#define PyObject_Bytes PyObject_Str -#endif /* Cache the values of {cP,p}ickle.{load,dump}s */ static PyObject *_PylibMC_pickle_loads = NULL; @@ -312,7 +292,7 @@ /* FIXME Failures are entirely silent. */ int rc; - /* n.b.: this is called wiile *not* holding the GIL, and must not + /* n.b.: this is called while *not* holding the GIL, and must not contain Python-API code */ ssize_t out_sz; @@ -537,9 +517,6 @@ return NULL; } -static void _PylibMC_cleanup_str_key_mapping(PyObject *key_str_map) { - Py_XDECREF(key_str_map); -} /* }}} */ static PyObject *_PylibMC_parse_memcached_value(PylibMC_Client *self, @@ -603,11 +580,7 @@ if (self->native_deserialization) { retval = _PylibMC_deserialize_native(self, NULL, value, size, flags); } else { -#if PY_MAJOR_VERSION >= 3 retval = PyObject_CallMethod((PyObject *)self, "deserialize", "y#I", value, size, (unsigned int) flags); -#else - retval = PyObject_CallMethod((PyObject *)self, "deserialize", "s#I", value, size, (unsigned int) flags); -#endif } #if USE_ZLIB @@ -1032,7 +1005,7 @@ PyMem_Free(serialized); } Py_XDECREF(key_prefix); - _PylibMC_cleanup_str_key_mapping(key_str_map); + Py_XDECREF(key_str_map); return failed; } @@ -1208,17 +1181,10 @@ if (PyTuple_Check(serval_and_flags)) { PyObject *flags_obj = PyTuple_GetItem(serval_and_flags, 1); if (flags_obj != NULL) { -#if PY_MAJOR_VERSION >= 3 if (PyLong_Check(flags_obj)) { *flags = (uint32_t) PyLong_AsLong(flags_obj); *dest = PyTuple_GetItem(serval_and_flags, 0); } -#else - if (PyInt_Check(flags_obj)) { - *flags = (uint32_t) PyInt_AsLong(flags_obj); - *dest = PyTuple_GetItem(serval_and_flags, 0); - } -#endif } } @@ -1260,24 +1226,11 @@ } else if (PyBool_Check(value_obj)) { 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; PyObject *tmp = PyObject_Str(value_obj); store_val = PyUnicode_AsEncodedString(tmp, "ascii", "strict"); Py_DECREF(tmp); -#else - } else if (PyInt_Check(value_obj)) { - store_flags |= PYLIBMC_FLAG_INTEGER; - PyObject* tmp = PyNumber_Int(value_obj); - store_val = PyObject_Bytes(tmp); - Py_DECREF(tmp); - } else if (PyLong_Check(value_obj)) { - store_flags |= PYLIBMC_FLAG_LONG; - PyObject* tmp = PyNumber_Long(value_obj); - store_val = PyObject_Bytes(tmp); - Py_DECREF(tmp); -#endif } else if (value_obj != NULL) { /* we have no idea what it is, so we'll store it pickled */ Py_INCREF(value_obj); @@ -1687,88 +1640,69 @@ } /* }}} */ -memcached_return pylibmc_memcached_fetch_multi(memcached_st *mc, pylibmc_mget_req req) { - /** - * Completely GIL-free multi getter - * - * Takes a set of keys given by *keys*, and stuffs the results into heap - * memory returned by *results*. - * - * If an error occured during retrieval, this function returns - * non-MEMCACHED_SUCCESS and *err_func* will point to a useful error - * function name. - * - * FIXME *results* is expected to be able to hold one more result than - * there are keys asked for, because of an implementation detail. - */ - - memcached_return rc; - *req.err_func = NULL; +static pylibmc_mget_res _fetch_multi(memcached_st *mc, + pylibmc_mget_req req) { + /* Completely GIL-free multi getter */ + pylibmc_mget_res res = { 0 }; - rc = memcached_mget(mc, (const char **)req.keys, req.key_lens, req.nkeys); + res.rc = memcached_mget(mc, (const char **)req.keys, req.key_lens, req.nkeys); - if (rc != MEMCACHED_SUCCESS) { - *req.err_func = "memcached_mget"; - return rc; + if (res.rc != MEMCACHED_SUCCESS) { + res.err_func = "memcached_mget"; + return res; } - /* Allocate as much as could possibly be needed, and an extra because of - * how libmemcached signals EOF. */ - *req.results = PyMem_New(memcached_result_st, req.nkeys + 1); + /* Allocate the results array, with room for libmemcached's sentinel. */ + res.results = PyMem_RawNew(memcached_result_st, req.nkeys + 1); /* Note that nresults will not be off by one with this because the loops * runs a half pass after the last key has been fetched, thus bumping the * count once. */ - for (*req.nresults = 0; ; (*req.nresults)++) { - memcached_result_st *res = memcached_result_create(mc, *req.results + *req.nresults); + for (res.nresults = 0; ; res.nresults++) { + memcached_result_st *result = memcached_result_create(mc, &res.results[res.nresults]); - /* if loop spins out of control, this fails */ - assert(req.nkeys >= (*req.nresults)); + assert(res.nresults <= req.nkeys); - res = memcached_fetch_result(mc, res, &rc); + result = memcached_fetch_result(mc, result, &res.rc); - if (res == NULL || rc == MEMCACHED_END) { + if (result == NULL || res.rc == MEMCACHED_END) { /* This is how libmecached signals EOF. */ break; - } else if (rc == MEMCACHED_BAD_KEY_PROVIDED - || rc == MEMCACHED_NO_KEY_PROVIDED) { + } else if (res.rc == MEMCACHED_BAD_KEY_PROVIDED + || res.rc == MEMCACHED_NO_KEY_PROVIDED) { continue; - } else if (rc != MEMCACHED_SUCCESS) { + } else if (res.rc != MEMCACHED_SUCCESS) { memcached_quit(mc); /* Reset fetch state */ - *req.err_func = "memcached_fetch"; - - /* Clean-up procedure */ - do { - memcached_result_free(*req.results + *req.nresults); - } while ((*req.nresults)--); - - PyMem_Free(*req.results); - *req.results = NULL; - *req.nresults = 0; - - return rc; + res.err_func = "memcached_fetch"; + _free_multi_result(res); } } - return MEMCACHED_SUCCESS; + res.rc = MEMCACHED_SUCCESS; + return res; } +static void _free_multi_result(pylibmc_mget_res res) { + if (res.results == NULL) + return; + for (Py_ssize_t i = 0; i < res.nresults; i++) { + memcached_result_free(&res.results[i]); + } + PyMem_RawDel(res.results); +} static PyObject *PylibMC_Client_get_multi( PylibMC_Client *self, PyObject *args, PyObject *kwds) { PyObject *key_seq, **key_objs, **orig_key_objs, *retval = NULL; char **keys, *prefix = NULL; - char *err_func = NULL; - memcached_result_st *res, *results = NULL; Py_ssize_t prefix_len = 0; Py_ssize_t i; PyObject *key_str_map = NULL; PyObject *temp_key_obj; size_t *key_lens; Py_ssize_t nkeys = 0, orig_nkeys = 0; - Py_ssize_t nresults = 0; - memcached_return rc; pylibmc_mget_req req; + pylibmc_mget_res res = { 0 }; static char *kws[] = { "keys", "key_prefix", NULL }; @@ -1812,7 +1746,7 @@ goto earlybird; } - /* normalization created an owned reference to ckey */ + /* Normalization created an owned reference to ckey */ PyBytes_AsStringAndSize(ckey, &key, &key_len); @@ -1824,7 +1758,7 @@ continue; } - /* determine rkey, the prefixed ckey */ + /* Determine rkey, the prefixed ckey */ if (prefix != NULL) { rkey = PyBytes_FromStringAndSize(prefix, prefix_len); PyBytes_Concat(&rkey, ckey); @@ -1855,40 +1789,29 @@ goto earlybird; } - /* TODO Make an iterator interface for getting each key separately. - * - * This would help large retrievals, as a single dictionary containing all - * the data at once isn't needed. (Should probably look into if it's even - * worth it.) - */ - Py_BEGIN_ALLOW_THREADS; - req.keys = keys; req.nkeys = (ssize_t) nkeys; req.key_lens = key_lens; - req.results = &results; - req.nresults = &nresults; - req.err_func = &err_func; - rc = pylibmc_memcached_fetch_multi(self->mc, req); + Py_BEGIN_ALLOW_THREADS; + res = _fetch_multi(self->mc, req); Py_END_ALLOW_THREADS; - if (rc != MEMCACHED_SUCCESS) { - PylibMC_ErrFromMemcached(self, err_func, rc); + if (res.rc != MEMCACHED_SUCCESS) { + PylibMC_ErrFromMemcached(self, res.err_func, res.rc); goto earlybird; } retval = PyDict_New(); - for (i = 0; i < nresults; i++) { + for (i = 0; i < res.nresults; i++) { PyObject *val, *key_obj; + memcached_result_st *result = &(res.results[i]); int rc; - res = results + i; - /* Long-winded, but this way we can handle NUL-bytes in keys. */ - key_obj = PyBytes_FromStringAndSize(memcached_result_key_value(res) + prefix_len, - memcached_result_key_length(res) - prefix_len); + key_obj = PyBytes_FromStringAndSize(memcached_result_key_value(result) + prefix_len, + memcached_result_key_length(result) - prefix_len); if (key_obj == NULL) goto loopcleanup; @@ -1901,7 +1824,7 @@ } /* Parse out value */ - val = _PylibMC_parse_memcached_result(self, res); + val = _PylibMC_parse_memcached_result(self, result); if (_PylibMC_cache_miss_simulated(val)) { Py_DECREF(key_obj); continue; @@ -1930,23 +1853,15 @@ Py_DECREF(orig_key_objs[i]); for (i = 0; i < nkeys; i++) Py_DECREF(key_objs[i]); - _PylibMC_cleanup_str_key_mapping(key_str_map); + Py_XDECREF(key_str_map); memory_cleanup: + PyMem_Free(key_objs); PyMem_Free(key_lens); PyMem_Free(keys); - PyMem_Free(key_objs); PyMem_Free(orig_key_objs); + _free_multi_result(res); - if (results != NULL) { - for (i = 0; i < nresults && results != NULL; i++) { - memcached_result_free(results + i); - } - PyMem_Free(results); - } - - /* Not INCREFing because the only two outcomes are NULL and a new dict. - * We're the owner of that dict already, so. */ return retval; } @@ -2494,11 +2409,7 @@ } 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 - return PyObject_CallFunction(_PylibMC_pickle_loads, "s#", buff, size); -#endif } static PyObject *_PylibMC_Unpickle_Bytes(PylibMC_Client *self, PyObject *val) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/src/_pylibmcmodule.h new/pylibmc-1.6.3/src/_pylibmcmodule.h --- old/pylibmc-1.6.1/src/_pylibmcmodule.h 2018-11-09 18:42:08.000000000 +0100 +++ new/pylibmc-1.6.3/src/_pylibmcmodule.h 2022-08-26 10:56:22.000000000 +0200 @@ -52,6 +52,16 @@ typedef ssize_t Py_ssize_t; #endif +/* Python 3.4 and up use PyMem_New/PyMem_Del to refer to the Python memory + * allocator which requires the GIL. These are our GIL free alternatives. */ +#if PY_VERSION_HEX >= 0x03040000 +# define PyMem_RawNew(type, nelem) ((type *)PyMem_RawMalloc((nelem)*sizeof(type))) +# define PyMem_RawDel(ptr) PyMem_RawFree(ptr) +#else +# define PyMem_RawNew PyMem_New +# define PyMem_RawDel(ptr) PyMem_Del +#endif + /* Server types. */ #define PYLIBMC_SERVER_TCP (1 << 0) #define PYLIBMC_SERVER_UDP (1 << 1) @@ -89,8 +99,6 @@ typedef memcached_return (*_PylibMC_IncrCommand)(memcached_st *, const char *, size_t, unsigned int, uint64_t*); -static PyObject *_exc_by_rc(memcached_return); - typedef struct { char *key; Py_ssize_t key_len; @@ -113,13 +121,16 @@ char **keys; Py_ssize_t nkeys; size_t *key_lens; - memcached_result_st **results; - Py_ssize_t *nresults; - char **err_func; - PyObject *transform; } pylibmc_mget_req; typedef struct { + memcached_return rc; + char *err_func; + memcached_result_st *results; + Py_ssize_t nresults; +} pylibmc_mget_res; + +typedef struct { char* key; Py_ssize_t key_len; _PylibMC_IncrCommand incr_func; @@ -135,6 +146,10 @@ int index; } _PylibMC_StatsContext; +static PyObject *_exc_by_rc(memcached_return); +static void _free_multi_result(pylibmc_mget_res); +static pylibmc_mget_res _fetch_multi(memcached_st *, pylibmc_mget_req); + /* {{{ Exceptions */ static PyObject *PylibMCExc_Error; static PyObject *PylibMCExc_CacheMiss; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/src/pylibmc/__main__.py new/pylibmc-1.6.3/src/pylibmc/__main__.py --- old/pylibmc-1.6.1/src/pylibmc/__main__.py 2018-11-09 18:42:08.000000000 +0100 +++ new/pylibmc-1.6.3/src/pylibmc/__main__.py 2022-08-26 10:56:22.000000000 +0200 @@ -18,17 +18,11 @@ outf.write(random.choice(tips) + "\n") def collect_servers(): - try: - in_addr = raw_input("Address [127.0.0.1]: ") - except NameError: - in_addr = input("Address [127.0.0.1]: ") + 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 NameError: - in_addr = input("Address [<stop>]: ") + in_addr = input("Address [<stop>]: ") else: yield "127.0.0.1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/src/pylibmc/autoconf.py new/pylibmc-1.6.3/src/pylibmc/autoconf.py --- old/pylibmc-1.6.1/src/pylibmc/autoconf.py 2018-11-09 18:42:08.000000000 +0100 +++ new/pylibmc-1.6.3/src/pylibmc/autoconf.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,6 +1,5 @@ "Autoconfiguration" -from __future__ import unicode_literals import pylibmc class UnsupportedAutoconfMethod(Exception): @@ -15,7 +14,7 @@ host, port = address.split(':') port = int(port) sock.connect((host, port)) - sock.send(('config get %s\r\n' % (key,)).encode('ascii')) + sock.send((f'config get {key}\r\n').encode('ascii')) state = 'wait-nl-header' nbytes = 0 buff = b'' @@ -48,7 +47,7 @@ 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] + return [f'{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'): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/src/pylibmc/client.py new/pylibmc-1.6.3/src/pylibmc/client.py --- old/pylibmc-1.6.1/src/pylibmc/client.py 2018-03-13 17:11:20.000000000 +0100 +++ new/pylibmc-1.6.3/src/pylibmc/client.py 2022-08-26 10:56:22.000000000 +0200 @@ -111,7 +111,7 @@ unknown = set(behaviors).difference(_all_behaviors_set) if unknown: names = ", ".join(map(str, sorted(unknown))) - raise ValueError("unknown behavior names: %s" % (names,)) + raise ValueError(f"unknown behavior names: {names}") if behaviors.get("hash") is not None: behaviors["hash"] = hashers[behaviors["hash"]] @@ -139,19 +139,19 @@ """ self.binary = binary self.addresses = list(servers) - super(Client, self).__init__(servers=translate_server_specs(servers), - binary=binary, - username=username, password=password, - behaviors=_behaviors_numeric(behaviors)) + super().__init__(servers=translate_server_specs(servers), + binary=binary, + username=username, password=password, + behaviors=_behaviors_numeric(behaviors)) def __repr__(self): - return "%s(%r, binary=%r)" % (self.__class__.__name__, - self.addresses, self.binary) + return "{}({!r}, binary={!r})".format(self.__class__.__name__, + self.addresses, self.binary) def __str__(self): addrs = ", ".join(map(str, self.addresses)) - return "<%s for %s, binary=%r>" % (self.__class__.__name__, - addrs, self.binary) + return "<{} for {}, binary={!r}>".format(self.__class__.__name__, + addrs, self.binary) # {{{ Mapping interface def __getitem__(self, key): @@ -163,7 +163,7 @@ def __setitem__(self, key, value): if not self.set(key, value): - raise KeyError("failed setting %r" % (key,)) + raise KeyError(f"failed setting {key!r}") def __delitem__(self, key): if not self.delete(key): @@ -180,7 +180,7 @@ Reverses the integer constants for `hash` and `distribution` into more understandable string values. See *set_behaviors* for info. """ - return BehaviorDict(self, _behaviors_symbolic(super(Client, self).get_behaviors())) + return BehaviorDict(self, _behaviors_symbolic(super().get_behaviors())) def set_behaviors(self, behaviors): """Sets the behaviors on the underlying C client instance. @@ -194,7 +194,7 @@ Translates old underscored behavior names to new ones for API leniency. """ - return super(Client, self).set_behaviors(_behaviors_numeric(behaviors)) + return super().set_behaviors(_behaviors_numeric(behaviors)) behaviors = property(get_behaviors, set_behaviors) @property @@ -203,7 +203,7 @@ # }}} def clone(self): - obj = super(Client, self).clone() + obj = super().clone() obj.addresses = list(self.addresses) obj.binary = self.binary return obj diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/src/pylibmc/consts.py new/pylibmc-1.6.3/src/pylibmc/consts.py --- old/pylibmc-1.6.1/src/pylibmc/consts.py 2015-06-17 13:21:50.000000000 +0200 +++ new/pylibmc-1.6.3/src/pylibmc/consts.py 2022-08-26 10:56:22.000000000 +0200 @@ -30,13 +30,13 @@ class BehaviorDict(dict): def __init__(self, client, *args, **kwds): - super(BehaviorDict, self).__init__(*args, **kwds) + super().__init__(*args, **kwds) self.client = client def __setitem__(self, name, value): - super(BehaviorDict, self).__setitem__(name, value) + super().__setitem__(name, value) self.client.set_behaviors({name: value}) def update(self, d): - super(BehaviorDict, self).update(d) + super().update(d) self.client.set_behaviors(d.copy()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/src/pylibmc/pools.py new/pylibmc-1.6.3/src/pylibmc/pools.py --- old/pylibmc-1.6.1/src/pylibmc/pools.py 2015-06-17 13:21:50.000000000 +0200 +++ new/pylibmc-1.6.3/src/pylibmc/pools.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,18 +1,13 @@ """Pooling""" -from __future__ import with_statement from contextlib import contextmanager +from queue import Queue try: import threading except ImportError: import dummy_threading as threading -try: - from Queue import Queue -except ImportError: - from queue import Queue - class ClientPool(Queue): """Client pooling helper. @@ -83,7 +78,7 @@ """ def __new__(cls, master): - return super(ThreadMappedPool, cls).__new__(cls) + return super().__new__(cls) def __init__(self, master): self.master = master diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/src/pylibmc/test.py new/pylibmc-1.6.3/src/pylibmc/test.py --- old/pylibmc-1.6.1/src/pylibmc/test.py 2015-06-17 13:21:50.000000000 +0200 +++ new/pylibmc-1.6.3/src/pylibmc/test.py 2022-08-26 10:56:22.000000000 +0200 @@ -34,7 +34,7 @@ vstr = b"VERSION " rnstr = b"\r\n" if not version.startswith(vstr) or not version.endswith(rnstr): - raise ValueError("unexpected version return: %r" % (version,)) + raise ValueError(f"unexpected version return: {version!r}") else: version = version[8:-2] return version @@ -42,7 +42,7 @@ def is_alive(addr): try: version = get_version(addr) - except (ValueError, socket.error): + except (ValueError, OSError): version = None return bool(version), version diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/src/pylibmc-version.h new/pylibmc-1.6.3/src/pylibmc-version.h --- old/pylibmc-1.6.1/src/pylibmc-version.h 2019-08-15 14:03:49.000000000 +0200 +++ new/pylibmc-1.6.3/src/pylibmc-version.h 2022-08-26 10:56:22.000000000 +0200 @@ -1 +1 @@ -#define PYLIBMC_VERSION "1.6.1" +#define PYLIBMC_VERSION "1.6.3" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/tests/__init__.py new/pylibmc-1.6.3/tests/__init__.py --- old/pylibmc-1.6.1/tests/__init__.py 2019-08-15 13:49:27.000000000 +0200 +++ new/pylibmc-1.6.3/tests/__init__.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,5 +1,4 @@ """Tests. They want YOU!!""" -from __future__ import print_function import gc import sys diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/tests/test_autoconf.py new/pylibmc-1.6.3/tests/test_autoconf.py --- old/pylibmc-1.6.1/tests/test_autoconf.py 2018-11-09 18:42:08.000000000 +0100 +++ new/pylibmc-1.6.3/tests/test_autoconf.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,21 +1,23 @@ +from pytest import raises 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) + with raises(autoconf.NoAutoconfFound): + mc = 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') + assert mc.set('a', 'b') + assert 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') + assert mc.set('a', 'b') + assert mc.get('a') == 'b' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/tests/test_client.py new/pylibmc-1.6.3/tests/test_client.py --- old/pylibmc-1.6.1/tests/test_client.py 2018-11-09 18:42:08.000000000 +0100 +++ new/pylibmc-1.6.3/tests/test_client.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,41 +1,42 @@ import functools -import sys import time + +from pytest import skip +from pytest import raises + import pylibmc import _pylibmc from pylibmc.test import make_test_client from tests import PylibmcTestCase -from nose import SkipTest -from nose.tools import eq_, ok_ -PY3 = sys.version_info[0] >= 3 def requires_memcached_touch(test): @functools.wraps(test) def wrapper(*args, **kwargs): if _pylibmc.libmemcached_version_hex >= 0x01000002: return test(*args, **kwargs) - raise SkipTest + skip('test requires touch functionality in libmemcached') return wrapper + class ClientTests(PylibmcTestCase): def test_zerokey(self): bc = make_test_client(binary=True) k = "\x00\x01" test_str = "test" - ok_(bc.set(k, test_str)) + assert bc.set(k, test_str) rk = next(iter(bc.get_multi([k]))) - eq_(k, rk) + assert k == rk def test_cas(self): c = "cas" k = "testkey" mc = make_test_client(binary=False, behaviors={c: True}) - ok_(mc.set(k, 0)) + assert mc.set(k, 0) while True: rv, cas = mc.gets(k) - ok_(mc.cas(k, rv + 1, cas)) + assert mc.cas(k, rv + 1, cas) if rv == 10: break @@ -56,58 +57,59 @@ expected_behaviors.append("dead_timeout") # Filter out private keys - actual_behaviors = [ - behavior for behavior in self.mc.behaviors - if not behavior.startswith('_')] + actual_behaviors = [behavior for behavior in self.mc.behaviors + if not behavior.startswith('_')] sorted_list = lambda L: list(sorted(L)) - eq_(sorted_list(expected_behaviors), - sorted_list(actual_behaviors)) + assert sorted_list(expected_behaviors) == \ + sorted_list(actual_behaviors) @requires_memcached_touch def test_touch(self): touch_test = "touch-test" touch_test2 = "touch-test-2" tval = "touch-val" - ok_(self.mc.set(touch_test, tval, 1)) - eq_(tval, self.mc.get(touch_test)) + assert self.mc.set(touch_test, tval, 1) + assert tval == self.mc.get(touch_test) time.sleep(2) - eq_(None, self.mc.get(touch_test)) + assert self.mc.get(touch_test) is None self.mc.set(touch_test, tval, 1) - eq_(tval, self.mc.get(touch_test)) - ok_(self.mc.touch(touch_test, 5)) + assert self.mc.get(touch_test) == tval + assert self.mc.touch(touch_test, 5) time.sleep(2) - eq_(tval, self.mc.get(touch_test)) + assert self.mc.get(touch_test) == tval - ok_(not self.mc.touch(touch_test2, 100)) + assert not self.mc.touch(touch_test2, 100) def test_exceptions(self): - self.assertRaises(TypeError, self.mc.set, 1, "hi") - self.assertRaises(_pylibmc.Error, _pylibmc.client, []) - self.assertRaises(_pylibmc.NotFound, self.mc.incr_multi, - ('a', 'b', 'c'), key_prefix='x', delta=1) + with raises(TypeError): + self.mc.set(1, "hi") + with raises(_pylibmc.Error): + _pylibmc.client([]) + with raises(_pylibmc.NotFound): + self.mc.incr_multi(('a', 'b', 'c'), key_prefix='x', delta=1) def test_utf8_encoding(self): k = "a key with a replacement character \ufffd and something non-BMP \U0001f4a3" k_enc = k.encode('utf-8') mc = make_test_client(binary=True) - ok_(mc.set(k, 0)) - ok_(mc.get(k_enc) == 0) + assert mc.set(k, 0) + assert 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) + assert mc.get(key) is 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) + assert mc.get('none-test') is None + assert mc.get('none-test', 'default') is None # formerly, this would raise a KeyError, which was incorrect - self.assertEqual(mc['none-test'], None) + assert mc['none-test'] is None assert 'none-test' in mc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/tests/test_cmemcached.py new/pylibmc-1.6.3/tests/test_cmemcached.py --- old/pylibmc-1.6.1/tests/test_cmemcached.py 2015-06-17 13:21:50.000000000 +0200 +++ new/pylibmc-1.6.3/tests/test_cmemcached.py 2022-08-26 10:56:22.000000000 +0200 @@ -4,7 +4,6 @@ # These are ported from cmemcached to ensure compatibility. import pylibmc -from nose.tools import eq_ from tests import PylibmcTestCase a = "a" @@ -20,9 +19,9 @@ class TestCmemcached(PylibmcTestCase): def testSetAndGet(self): self.mc.set(num12345, 12345) - eq_(self.mc.get(num12345), 12345) + assert self.mc.get(num12345) == 12345 self.mc.set(str12345, n12345) - eq_(self.mc.get(str12345), n12345) + assert self.mc.get(str12345) == n12345 def testDelete(self): self.mc.set(str12345, n12345) @@ -42,10 +41,10 @@ self.mc.set("b", "valueB") self.mc.set("c", "valueC") result = self.mc.get_multi(["a", "b", "c", "", "hello world"]) - eq_(result, {'a': 'valueA', 'b': 'valueB', 'c': 'valueC'}) + assert result == {'a': 'valueA', 'b': 'valueB', 'c': 'valueC'} def testBigGetMulti(self): - count = 10 ** 4 + count = 10 ** 3 # Python 2: .encode() is a no-op on these byte strings since they # only contain bytes that can be implicitly decoded as ASCII. keys = ['key%d' % i for i in range(count)] @@ -56,7 +55,7 @@ d[key] = value self.mc.set(key, value) result = self.mc.get_multi(keys) - eq_(result, d) + assert result == d def testFunnyDelete(self): s = "" @@ -66,10 +65,10 @@ self.mc.delete(a) self.mc.set(a, I_) assert self.mc.append(a, Do) - eq_(self.mc.get(a), I_Do) + assert self.mc.get(a) == I_Do def testPrepend(self): self.mc.delete(a) self.mc.set(a, Do) assert self.mc.prepend(a, I_) - eq_(self.mc.get(a), I_Do) + assert self.mc.get(a) == I_Do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/tests/test_pooling.py new/pylibmc-1.6.3/tests/test_pooling.py --- old/pylibmc-1.6.1/tests/test_pooling.py 2015-06-17 13:21:50.000000000 +0200 +++ new/pylibmc-1.6.3/tests/test_pooling.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,11 +1,8 @@ -try: - import queue -except ImportError: - import Queue as queue +import queue import pylibmc -from nose.tools import eq_, ok_ from tests import PylibmcTestCase +from pytest import raises class PoolTestCase(PylibmcTestCase): pass @@ -15,21 +12,27 @@ a_str = "a" p = pylibmc.ClientPool(self.mc, 2) with p.reserve() as smc: - ok_(smc) - ok_(smc.set(a_str, 1)) - eq_(smc[a_str], 1) + assert smc + assert smc.set(a_str, 1) + assert smc[a_str] == 1 def test_exhaust(self): p = pylibmc.ClientPool(self.mc, 2) - with p.reserve() as smc1: - with p.reserve() as smc2: - self.assertRaises(queue.Empty, p.reserve().__enter__) + with p.reserve() as mc1: + assert mc1 is not None + with p.reserve() as mc2: + assert mc2 is not None + assert mc2 is not mc1 + with raises(queue.Empty): + # This third time will fail. + with p.reserve(): + pass class ThreadMappedPoolTests(PoolTestCase): def test_simple(self): a_str = "a" p = pylibmc.ThreadMappedPool(self.mc) with p.reserve() as smc: - ok_(smc) - ok_(smc.set(a_str, 1)) - eq_(smc[a_str], 1) + assert smc + assert smc.set(a_str, 1) + assert smc[a_str] == 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/tests/test_refcounts.py new/pylibmc-1.6.3/tests/test_refcounts.py --- old/pylibmc-1.6.1/tests/test_refcounts.py 2019-08-15 13:49:27.000000000 +0200 +++ new/pylibmc-1.6.3/tests/test_refcounts.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,10 +1,5 @@ -from __future__ import unicode_literals -from __future__ import print_function - import datetime -from nose.tools import eq_, ok_ - import pylibmc import _pylibmc from pylibmc.test import make_test_client @@ -33,9 +28,9 @@ refcountables = [key, val] initial_refcounts = get_refcounts(refcountables) bc.set(key, val) - eq_(get_refcounts(refcountables), initial_refcounts) - eq_(bc.get(key), val) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts + assert bc.get(key) == val + assert get_refcounts(refcountables) == initial_refcounts def test_get_complex_type(self): self._test_get("refcountest", datetime.datetime.fromtimestamp(0)) @@ -54,16 +49,16 @@ refcountables = [key, val, default] initial_refcounts = get_refcounts(refcountables) bc.set(key, val) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts assert bc.get(key) == val - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts assert bc.get(key, default) == val - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete(key) assert bc.get(key) is None - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts assert bc.get(key, default) is default - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts def test_get_multi(self): bc = make_test_client(binary=True) @@ -72,21 +67,21 @@ refcountables = keys + [value] initial_refcounts = get_refcounts(refcountables) bc.set(keys[0], value) - eq_(get_refcounts(refcountables), initial_refcounts) - eq_(bc.get_multi(keys), {keys[0]: value}) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts + assert bc.get_multi(keys) == {keys[0]: value} + assert get_refcounts(refcountables) == initial_refcounts def test_get_multi_bytes_and_unicode(self): bc = make_test_client(binary=True) keys = ["third", b"fourth"] value = "another_value" - kv = dict((k, value) for k in keys) + kv = {k: value for k in keys} refcountables = [keys] + [value] initial_refcounts = get_refcounts(refcountables) bc.set_multi(kv) - eq_(get_refcounts(refcountables), initial_refcounts) - eq_(bc.get_multi(keys)[keys[0]], value) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts + assert bc.get_multi(keys)[keys[0]] == value + assert get_refcounts(refcountables) == initial_refcounts def test_delete(self): bc = make_test_client(binary=True) @@ -96,17 +91,17 @@ initial_refcounts = get_refcounts(refcountables) bc.set(keys[0], values[0]) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.set(keys[1], values[1]) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete(keys[0]) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete(keys[1]) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete(keys[0]) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete(keys[1]) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts def test_incr(self): bc = make_test_client(binary=True) @@ -115,13 +110,13 @@ initial_refcounts = get_refcounts(refcountables) bc.set(keys[0], 1) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.incr(keys[0]) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.set(keys[1], 5) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.incr(keys[1]) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts def test_set_and_delete_multi(self): bc = make_test_client(binary=True) @@ -131,17 +126,17 @@ initial_refcounts = get_refcounts(refcountables) bc.set_multi(dict(zip(keys, values))) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete_multi([keys[0]]) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete_multi([keys[1]]) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.set_multi(dict(zip(keys, values))) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete_multi(keys) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete_multi(keys) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts def test_prefixes(self): bc = make_test_client(binary=True) @@ -152,19 +147,19 @@ initial_refcounts = get_refcounts(refcountables) bc.set_multi(dict(zip(keys, values)), key_prefix=prefix) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.get_multi(keys, key_prefix=prefix) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete_multi([keys[0]], key_prefix=prefix) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete_multi([keys[1]], key_prefix=prefix) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.set_multi(dict(zip(keys, values)), key_prefix=prefix) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete_multi(keys, key_prefix=prefix) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts bc.delete_multi(keys, key_prefix=prefix) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts def test_get_invalid_key(self): bc = make_test_client(binary=True) @@ -176,7 +171,7 @@ except TypeError: raised = True assert raised - eq_(get_refcounts([key]), initial_refcount) + assert get_refcounts([key]) == initial_refcount def test_cas(self): k = "testkey" @@ -185,12 +180,12 @@ refcountables = [k, val] initial_refcounts = get_refcounts(refcountables) - ok_(mc.set(k, 0)) - eq_(get_refcounts(refcountables), initial_refcounts) + assert mc.set(k, 0) + assert get_refcounts(refcountables) == initial_refcounts while True: rv, cas = mc.gets(k) - eq_(get_refcounts(refcountables), initial_refcounts) - ok_(mc.cas(k, rv + 1, cas)) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts + assert mc.cas(k, rv + 1, cas) + assert get_refcounts(refcountables) == initial_refcounts if rv == 10: break diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/tests/test_serialization.py new/pylibmc-1.6.3/tests/test_serialization.py --- old/pylibmc-1.6.1/tests/test_serialization.py 2018-11-09 18:42:08.000000000 +0100 +++ new/pylibmc-1.6.3/tests/test_serialization.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,13 +1,6 @@ -# -*- coding: utf-8 -*- - -from __future__ import unicode_literals -from __future__ import print_function - import datetime import json -import sys - -from nose.tools import eq_, ok_ +import pickle import pylibmc import _pylibmc @@ -15,37 +8,20 @@ from tests import PylibmcTestCase from tests import get_refcounts -try: - import cPickle as pickle -except ImportError: - import pickle - -def long_(val): - try: - return long(val) - except NameError: - # 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.""" def test_integers(self): c = make_test_client(binary=True) - if sys.version_info[0] == 3: - eq_(c.serialize(1), (b'1', f_long)) - eq_(c.serialize(2**64), (b'18446744073709551616', f_long)) - else: - eq_(c.serialize(1), (b'1', f_int)) - eq_(c.serialize(2**64), (b'18446744073709551616', f_long)) - - eq_(c.deserialize(b'1', f_int), 1) - - eq_(c.deserialize(b'18446744073709551616', f_long), 2**64) - eq_(c.deserialize(b'1', f_long), long_(1)) + assert c.serialize(1) == (b'1', f_long) + assert c.serialize(2**64) == (b'18446744073709551616', f_long) + assert c.deserialize(b'18446744073709551616', f_long) == 2**64 + assert c.deserialize(b'1', f_long) == 1 def test_nonintegers(self): # tuples (python_value, (expected_bytestring, expected_flags)) @@ -58,8 +34,8 @@ (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)), + ('åäö', ('åäö'.encode(), f_text)), + ('', (b'', f_text)), # objects (datetime.date(2015, 12, 28), (pickle.dumps(datetime.date(2015, 12, 28), protocol=-1), f_pickle)), @@ -67,8 +43,8 @@ c = make_test_client(binary=True) for value, serialized_value in SERIALIZATION_TEST_VALUES: - eq_(c.serialize(value), serialized_value) - eq_(c.deserialize(*serialized_value), value) + assert c.serialize(value) == serialized_value + assert c.deserialize(*serialized_value) == value class SerializationTests(PylibmcTestCase): @@ -80,13 +56,13 @@ def deserialize(self, bytes_, flags): try: - return super(MyClient, self).deserialize(bytes_, flags) + return super().deserialize(bytes_, flags) except Exception as error: self.ignored.append(error) raise pylibmc.CacheMiss global MyObject # Needed by the pickling system. - class MyObject(object): + class MyObject: def __getstate__(self): return dict(a=1) def __eq__(self, other): @@ -95,7 +71,7 @@ assert d['a'] == 1 c = make_test_client(MyClient, behaviors={'cas': True}) - eq_(c.get('notathing'), None) + assert c.get('notathing') is None refcountables = ['foo', 'myobj', 'noneobj', 'myobj2', 'cachemiss'] initial_refcounts = get_refcounts(refcountables) @@ -106,27 +82,27 @@ c['myobj2'] = MyObject() # Show that everything is initially regular. - eq_(c.get('myobj'), MyObject()) - eq_(get_refcounts(refcountables), initial_refcounts) - eq_(c.get_multi(['foo', 'myobj', 'noneobj', 'cachemiss']), + assert c.get('myobj') == MyObject() + assert get_refcounts(refcountables) == initial_refcounts + assert (c.get_multi(['foo', 'myobj', 'noneobj', 'cachemiss']) == dict(foo='foo', myobj=MyObject(), noneobj=None)) - eq_(get_refcounts(refcountables), initial_refcounts) - eq_(c.gets('myobj2')[0], MyObject()) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts + assert c.gets('myobj2')[0] == MyObject() + assert get_refcounts(refcountables) == initial_refcounts # Show that the subclass can transform unpickling issues into a cache miss. del MyObject # Break unpickling - eq_(c.get('myobj'), None) - eq_(get_refcounts(refcountables), initial_refcounts) - eq_(c.get_multi(['foo', 'myobj', 'noneobj', 'cachemiss']), + assert c.get('myobj') is None + assert get_refcounts(refcountables) == initial_refcounts + assert (c.get_multi(['foo', 'myobj', 'noneobj', 'cachemiss']) == dict(foo='foo', noneobj=None)) - eq_(get_refcounts(refcountables), initial_refcounts) - eq_(c.gets('myobj2'), (None, None)) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts + assert c.gets('myobj2') == (None, None) + assert get_refcounts(refcountables) == initial_refcounts # The ignored errors are "AttributeError: test.test_client has no MyObject" - eq_(len(MyClient.ignored), 3) + assert len(MyClient.ignored) == 3 assert all(isinstance(error, AttributeError) for error in MyClient.ignored) def test_refcounts(self): @@ -144,18 +120,18 @@ def deserialize(self, bytes_, flags): return SENTINEL - refcountables = [1, long_(1), SENTINEL, DUMMY, KEY, VALUE] + refcountables = [1, SENTINEL, DUMMY, KEY, VALUE] c = make_test_client(MyClient) initial_refcounts = get_refcounts(refcountables) c.set(KEY, VALUE) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts assert c.get(KEY) is SENTINEL - eq_(get_refcounts(refcountables), initial_refcounts) - eq_(c.get_multi([KEY]), {KEY: SENTINEL}) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts + assert c.get_multi([KEY]) == {KEY: SENTINEL} + assert get_refcounts(refcountables) == initial_refcounts c.set_multi({KEY: True}) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts def test_override_serialize(self): class MyClient(pylibmc.Client): @@ -169,7 +145,7 @@ c = make_test_client(MyClient) c['foo'] = (1, 2, 3, 4) # json turns tuples into lists: - eq_(c['foo'], [1, 2, 3, 4]) + assert c['foo'] == [1, 2, 3, 4] raised = False try: @@ -206,7 +182,7 @@ c = make_test_client(MyClient) initial_refcounts = get_refcounts(refcountables) self._assert_set_raises(c, KEY, VALUE) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts def test_invalid_flags_returned_2(self): DUMMY = "ab" @@ -222,11 +198,11 @@ initial_refcounts = get_refcounts(refcountables) self._assert_set_raises(c, KEY, VALUE) - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts try: c.set_multi({KEY: DUMMY}) except ValueError: raised = True assert raised - eq_(get_refcounts(refcountables), initial_refcounts) + assert get_refcounts(refcountables) == initial_refcounts diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylibmc-1.6.1/tests/test_translate.py new/pylibmc-1.6.3/tests/test_translate.py --- old/pylibmc-1.6.1/tests/test_translate.py 2015-06-17 13:21:50.000000000 +0200 +++ new/pylibmc-1.6.3/tests/test_translate.py 2022-08-26 10:56:22.000000000 +0200 @@ -1,32 +1,11 @@ -from nose.tools import eq_ from pylibmc.client import translate_server_spec import _pylibmc def test_translate(): - eq_(translate_server_spec("111.122.133.144"), - (_pylibmc.server_type_tcp, "111.122.133.144", 11211, 1)) - -def test_translate(): - eq_(translate_server_spec("111.122.133.144:5555"), - (_pylibmc.server_type_tcp, "111.122.133.144", 5555, 1)) - -def test_udp_translate(): - eq_(translate_server_spec("udp:199.299.399.499:5555"), - (_pylibmc.server_type_udp, "199.299.399.499", 5555, 1)) - -def test_udp_translate_ipv6(): - eq_(translate_server_spec("udp:[abcd:abcd::1]:5555"), - (_pylibmc.server_type_udp, "abcd:abcd::1", 5555, 1)) - -def test_translate_with_weight_string(): - eq_(translate_server_spec("111.122.133.144:5555:2"), - (_pylibmc.server_type_tcp, "111.122.133.144", 5555, 2)) - -def test_translate_with_weight_kwd(): - eq_(translate_server_spec("111.122.133.144", weight=2), - (_pylibmc.server_type_tcp, "111.122.133.144", 11211, 2)) - -def test_udp_translate_ipv6_with_weight(): - eq_(translate_server_spec("udp:[abcd:abcd::1]:5555:2"), - (_pylibmc.server_type_udp, "abcd:abcd::1", 5555, 2)) - + assert (translate_server_spec("111.122.133.144") == (_pylibmc.server_type_tcp, "111.122.133.144", 11211, 1)) + assert (translate_server_spec("111.122.133.144:5555") == (_pylibmc.server_type_tcp, "111.122.133.144", 5555, 1)) + assert (translate_server_spec("udp:199.299.399.499:5555") == (_pylibmc.server_type_udp, "199.299.399.499", 5555, 1)) + assert (translate_server_spec("udp:[abcd:abcd::1]:5555") == (_pylibmc.server_type_udp, "abcd:abcd::1", 5555, 1)) + assert (translate_server_spec("111.122.133.144:5555:2") == (_pylibmc.server_type_tcp, "111.122.133.144", 5555, 2)) + assert (translate_server_spec("111.122.133.144", weight=2) == (_pylibmc.server_type_tcp, "111.122.133.144", 11211, 2)) + assert (translate_server_spec("udp:[abcd:abcd::1]:5555:2") == (_pylibmc.server_type_udp, "abcd:abcd::1", 5555, 2))