Hello community,
here is the log from the commit of package python-pymemcache for
openSUSE:Factory checked in at 2019-09-11 10:36:44
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pymemcache (Old)
and /work/SRC/openSUSE:Factory/.python-pymemcache.new.7948 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pymemcache"
Wed Sep 11 10:36:44 2019 rev:4 rq:729846 version:2.2.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pymemcache/python-pymemcache.changes
2019-03-19 10:03:17.559785759 +0100
+++
/work/SRC/openSUSE:Factory/.python-pymemcache.new.7948/python-pymemcache.changes
2019-09-11 10:36:46.543272143 +0200
@@ -1,0 +2,14 @@
+Tue Sep 10 11:58:40 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 2.2.2:
+ * Fix long_description string in Python packaging.
+ * Fix flags when setting multiple differently-typed values at once.
+ * Use setup.cfg metadata instead setup.py config to generate package.
+ * Add default_noreply parameter to HashClient.
+ * Add encoding parameter to Client constructors (defaults to ascii).
+ * Add flags parameter to write operation methods.
+ * Handle unicode key values in MockMemcacheClient correctly.
+ * Improve ASCII encoding failure exception.
+ * Fix setup.py dependency on six already being installed.
+
+-------------------------------------------------------------------
Old:
----
pymemcache-2.1.1.tar.gz
New:
----
pymemcache-2.2.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pymemcache.spec ++++++
--- /var/tmp/diff_new_pack.zjHKWo/_old 2019-09-11 10:36:47.771271786 +0200
+++ /var/tmp/diff_new_pack.zjHKWo/_new 2019-09-11 10:36:47.807271777 +0200
@@ -19,25 +19,25 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-pymemcache
-Version: 2.1.1
+Version: 2.2.2
Release: 0
Summary: A pure Python memcached client
License: Apache-2.0
Group: Development/Languages/Python
-Url: https://github.com/Pinterest/pymemcache
+URL: https://github.com/Pinterest/pymemcache
Source:
https://files.pythonhosted.org/packages/source/p/pymemcache/pymemcache-%{version}.tar.gz
BuildRequires: %{python_module mock}
BuildRequires: %{python_module pytest}
BuildRequires: %{python_module setuptools}
BuildRequires: %{python_module six}
+BuildRequires: fdupes
+BuildRequires: python-rpm-macros
+Requires: python-six
+BuildArch: noarch
%ifpython2
BuildRequires: python2-future
Requires: python2-future
%endif
-BuildRequires: python-rpm-macros
-Requires: python-six
-BuildArch: noarch
-
%python_subpackages
%description
@@ -59,12 +59,12 @@
%install
%python_install
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
%check
%python_exec setup.py test
%files %{python_files}
-%defattr(-,root,root,-)
%license LICENSE.txt
%doc README.rst
%{python_sitelib}/*
++++++ pymemcache-2.1.1.tar.gz -> pymemcache-2.2.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/ChangeLog.rst
new/pymemcache-2.2.2/ChangeLog.rst
--- old/pymemcache-2.1.1/ChangeLog.rst 2019-01-28 18:34:10.000000000 +0100
+++ new/pymemcache-2.2.2/ChangeLog.rst 2019-08-06 21:06:33.000000000 +0200
@@ -1,5 +1,23 @@
-Change Log
-==========
+Changelog
+=========
+
+New in version 2.2.2
+--------------------
+* Fix ``long_description`` string in Python packaging.
+
+New in version 2.2.1
+--------------------
+* Fix ``flags`` when setting multiple differently-typed values at once.
+
+New in version 2.2.0
+--------------------
+* Drop official support for Python 3.4.
+* Use ``setup.cfg`` metadata instead ``setup.py`` config to generate package.
+* Add ``default_noreply`` parameter to ``HashClient``.
+* Add ``encoding`` parameter to ``Client`` constructors (defaults to
``ascii``).
+* Add ``flags`` parameter to write operation methods.
+* Handle unicode key values in ``MockMemcacheClient`` correctly.
+* Improve ASCII encoding failure exception.
New in version 2.1.1
--------------------
@@ -58,8 +76,8 @@
New in version 1.4.0
--------------------
-* Unicode keys support. It is now possible to pass the flag
`allow_unicode_keys` when creating the clients, thanks @jogo!
-* Fixed a bug where PooledClient wasn't following `default_noreply` arg set on
init, thanks @kols!
+* Unicode keys support. It is now possible to pass the flag
``allow_unicode_keys`` when creating the clients, thanks @jogo!
+* Fixed a bug where PooledClient wasn't following ``default_noreply`` arg set
on init, thanks @kols!
* Improved documentation
New in version 1.3.8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/MANIFEST.in
new/pymemcache-2.2.2/MANIFEST.in
--- old/pymemcache-2.1.1/MANIFEST.in 2018-09-07 17:11:46.000000000 +0200
+++ new/pymemcache-2.2.2/MANIFEST.in 2019-08-06 21:06:33.000000000 +0200
@@ -2,4 +2,3 @@
recursive-include pymemcache *.py
global-exclude *.pyc
global-exclude *.pyo
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/PKG-INFO
new/pymemcache-2.2.2/PKG-INFO
--- old/pymemcache-2.1.1/PKG-INFO 2019-01-28 18:34:49.000000000 +0100
+++ new/pymemcache-2.2.2/PKG-INFO 2019-08-06 21:07:47.000000000 +0200
@@ -1,8 +1,8 @@
-Metadata-Version: 1.1
+Metadata-Version: 2.1
Name: pymemcache
-Version: 2.1.1
-Summary: A comprehensive, fast, pure Python memcached client
-Home-page: https://github.com/Pinterest/pymemcache
+Version: 2.2.2
+Summary: "A comprehensive, fast, pure Python memcached client"
+Home-page: https://github.com/pinterest/pymemcache
Author: Charles Gordon
Author-email: [email protected]
License: Apache License 2.0
@@ -56,6 +56,13 @@
See the documentation here:
https://pymemcache.readthedocs.io/en/latest/
+ Django
+ ------
+
+ If you're planning on using pymemcache with Django, you might be
interested in
+ `django-pymemcache
<https://github.com/django-pymemcache/django-pymemcache>`_.
+ It provides a Django cache backend that is built on pymemcache.
+
Comparison with Other Libraries
===============================
@@ -133,8 +140,26 @@
Are you really excited about open-source? Or great software
engineering?
Pinterest is `hiring <https://careers.pinterest.com/>`_!
- Change Log
- ==========
+ Changelog
+ =========
+
+ New in version 2.2.2
+ --------------------
+ * Fix ``long_description`` string in Python packaging.
+
+ New in version 2.2.1
+ --------------------
+ * Fix ``flags`` when setting multiple differently-typed values at once.
+
+ New in version 2.2.0
+ --------------------
+ * Drop official support for Python 3.4.
+ * Use ``setup.cfg`` metadata instead ``setup.py`` config to generate
package.
+ * Add ``default_noreply`` parameter to ``HashClient``.
+ * Add ``encoding`` parameter to ``Client`` constructors (defaults to
``ascii``).
+ * Add ``flags`` parameter to write operation methods.
+ * Handle unicode key values in ``MockMemcacheClient`` correctly.
+ * Improve ASCII encoding failure exception.
New in version 2.1.1
--------------------
@@ -193,8 +218,8 @@
New in version 1.4.0
--------------------
- * Unicode keys support. It is now possible to pass the flag
`allow_unicode_keys` when creating the clients, thanks @jogo!
- * Fixed a bug where PooledClient wasn't following `default_noreply`
arg set on init, thanks @kols!
+ * Unicode keys support. It is now possible to pass the flag
``allow_unicode_keys`` when creating the clients, thanks @jogo!
+ * Fixed a bug where PooledClient wasn't following ``default_noreply``
arg set on init, thanks @kols!
* Improved documentation
New in version 1.3.8
@@ -245,13 +270,14 @@
--------------------
* Introduced PooledClient a thread-safe pool of clients
+Keywords: memcache,client,database
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
-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 :: Implementation :: PyPy
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Topic :: Database
+Description-Content-Type: text/x-rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/README.rst
new/pymemcache-2.2.2/README.rst
--- old/pymemcache-2.1.1/README.rst 2019-01-08 16:29:27.000000000 +0100
+++ new/pymemcache-2.2.2/README.rst 2019-04-20 01:32:18.000000000 +0200
@@ -48,6 +48,13 @@
See the documentation here: https://pymemcache.readthedocs.io/en/latest/
+Django
+------
+
+If you're planning on using pymemcache with Django, you might be interested in
+`django-pymemcache <https://github.com/django-pymemcache/django-pymemcache>`_.
+It provides a Django cache backend that is built on pymemcache.
+
Comparison with Other Libraries
===============================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/pymemcache/__init__.py
new/pymemcache-2.2.2/pymemcache/__init__.py
--- old/pymemcache-2.1.1/pymemcache/__init__.py 2019-01-28 18:34:10.000000000
+0100
+++ new/pymemcache-2.2.2/pymemcache/__init__.py 2019-08-06 21:06:33.000000000
+0200
@@ -1,4 +1,4 @@
-__version__ = '2.1.1'
+__version__ = '2.2.2'
from pymemcache.client.base import Client # noqa
from pymemcache.client.base import PooledClient # noqa
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/pymemcache/client/base.py
new/pymemcache-2.2.2/pymemcache/client/base.py
--- old/pymemcache-2.1.1/pymemcache/client/base.py 2019-01-08
18:10:49.000000000 +0100
+++ new/pymemcache-2.2.2/pymemcache/client/base.py 2019-08-05
21:52:32.000000000 +0200
@@ -93,18 +93,18 @@
else:
key = key.encode('ascii')
except (UnicodeEncodeError, UnicodeDecodeError):
- raise MemcacheIllegalInputError("Non-ASCII key: '%r'" % key)
+ raise MemcacheIllegalInputError("Non-ASCII key: %r" % key)
key = key_prefix + key
parts = key.split()
if len(key) > 250:
- raise MemcacheIllegalInputError("Key is too long: '%r'" % key)
+ raise MemcacheIllegalInputError("Key is too long: %r" % key)
# second statement catches leading or trailing whitespace
elif len(parts) > 1 or parts[0] != key:
- raise MemcacheIllegalInputError("Key contains whitespace: '%r'" % key)
+ raise MemcacheIllegalInputError("Key contains whitespace: %r" % key)
elif b'\00' in key:
- raise MemcacheIllegalInputError("Key contains null: '%r'" % key)
+ raise MemcacheIllegalInputError("Key contains null: %r" % key)
return key
@@ -175,19 +175,27 @@
raise Exception("Unknown flags for value: {1}".format(flags))
+ .. note::
+
+ Most write operations allow the caller to provide a ``flags`` value to
+ support advanced interaction with the server. This will **override** the
+ "flags" value returned by the serializer and should therefore only be
+ used when you have a complete understanding of how the value should be
+ serialized, stored, and deserialized.
+
*Error Handling*
All of the methods in this class that talk to memcached can throw one of
the following exceptions:
- * MemcacheUnknownCommandError
- * MemcacheClientError
- * MemcacheServerError
- * MemcacheUnknownError
- * MemcacheUnexpectedCloseError
- * MemcacheIllegalInputError
- * socket.timeout
- * socket.error
+ * :class:`pymemcache.exceptions.MemcacheUnknownCommandError`
+ * :class:`pymemcache.exceptions.MemcacheClientError`
+ * :class:`pymemcache.exceptions.MemcacheServerError`
+ * :class:`pymemcache.exceptions.MemcacheUnknownError`
+ * :class:`pymemcache.exceptions.MemcacheUnexpectedCloseError`
+ * :class:`pymemcache.exceptions.MemcacheIllegalInputError`
+ * :class:`socket.timeout`
+ * :class:`socket.error`
Instances of this class maintain a persistent connection to memcached
which is terminated when any of these exceptions are raised. The next
@@ -206,7 +214,8 @@
socket_module=socket,
key_prefix=b'',
default_noreply=True,
- allow_unicode_keys=False):
+ allow_unicode_keys=False,
+ encoding='ascii'):
"""
Constructor.
@@ -233,6 +242,7 @@
store commands (except from cas, incr, and decr, which default to
False).
allow_unicode_keys: bool, support unicode (utf8) keys
+ encoding: optional str, controls data encoding (defaults to 'ascii').
Notes:
The constructor does not make a connection to memcached. The first
@@ -254,6 +264,7 @@
self.key_prefix = key_prefix
self.default_noreply = default_noreply
self.allow_unicode_keys = allow_unicode_keys
+ self.encoding = encoding
def check_key(self, key):
"""Checks key and add key_prefix."""
@@ -293,7 +304,7 @@
finally:
self.sock = None
- def set(self, key, value, expire=0, noreply=None):
+ def set(self, key, value, expire=0, noreply=None, flags=None):
"""
The memcached "set" command.
@@ -304,6 +315,8 @@
from the cache, or zero for no expiry (the default).
noreply: optional bool, True to not wait for the reply (defaults to
self.default_noreply).
+ flags: optional int, arbitrary bit field used for server-specific
+ flags
Returns:
If no exception is raised, always returns True. If an exception is
@@ -312,9 +325,10 @@
"""
if noreply is None:
noreply = self.default_noreply
- return self._store_cmd(b'set', {key: value}, expire, noreply)[key]
+ return self._store_cmd(b'set', {key: value}, expire, noreply,
+ flags=flags)[key]
- def set_many(self, values, expire=0, noreply=None):
+ def set_many(self, values, expire=0, noreply=None, flags=None):
"""
A convenience function for setting multiple values.
@@ -325,6 +339,8 @@
from the cache, or zero for no expiry (the default).
noreply: optional bool, True to not wait for the reply (defaults to
self.default_noreply).
+ flags: optional int, arbitrary bit field used for server-specific
+ flags
Returns:
Returns a list of keys that failed to be inserted.
@@ -332,12 +348,12 @@
"""
if noreply is None:
noreply = self.default_noreply
- result = self._store_cmd(b'set', values, expire, noreply)
+ result = self._store_cmd(b'set', values, expire, noreply, flags=flags)
return [k for k, v in six.iteritems(result) if not v]
set_multi = set_many
- def add(self, key, value, expire=0, noreply=None):
+ def add(self, key, value, expire=0, noreply=None, flags=None):
"""
The memcached "add" command.
@@ -348,6 +364,8 @@
from the cache, or zero for no expiry (the default).
noreply: optional bool, True to not wait for the reply (defaults to
self.default_noreply).
+ flags: optional int, arbitrary bit field used for server-specific
+ flags
Returns:
If noreply is True, the return value is always True. Otherwise the
@@ -356,9 +374,10 @@
"""
if noreply is None:
noreply = self.default_noreply
- return self._store_cmd(b'add', {key: value}, expire, noreply)[key]
+ return self._store_cmd(b'add', {key: value}, expire, noreply,
+ flags=flags)[key]
- def replace(self, key, value, expire=0, noreply=None):
+ def replace(self, key, value, expire=0, noreply=None, flags=None):
"""
The memcached "replace" command.
@@ -369,6 +388,8 @@
from the cache, or zero for no expiry (the default).
noreply: optional bool, True to not wait for the reply (defaults to
self.default_noreply).
+ flags: optional int, arbitrary bit field used for server-specific
+ flags
Returns:
If noreply is True, always returns True. Otherwise returns True if
@@ -377,9 +398,10 @@
"""
if noreply is None:
noreply = self.default_noreply
- return self._store_cmd(b'replace', {key: value}, expire, noreply)[key]
+ return self._store_cmd(b'replace', {key: value}, expire, noreply,
+ flags=flags)[key]
- def append(self, key, value, expire=0, noreply=None):
+ def append(self, key, value, expire=0, noreply=None, flags=None):
"""
The memcached "append" command.
@@ -390,15 +412,18 @@
from the cache, or zero for no expiry (the default).
noreply: optional bool, True to not wait for the reply (defaults to
self.default_noreply).
+ flags: optional int, arbitrary bit field used for server-specific
+ flags
Returns:
True.
"""
if noreply is None:
noreply = self.default_noreply
- return self._store_cmd(b'append', {key: value}, expire, noreply)[key]
+ return self._store_cmd(b'append', {key: value}, expire, noreply,
+ flags=flags)[key]
- def prepend(self, key, value, expire=0, noreply=None):
+ def prepend(self, key, value, expire=0, noreply=None, flags=None):
"""
The memcached "prepend" command.
@@ -409,15 +434,18 @@
from the cache, or zero for no expiry (the default).
noreply: optional bool, True to not wait for the reply (defaults to
self.default_noreply).
+ flags: optional int, arbitrary bit field used for server-specific
+ flags
Returns:
True.
"""
if noreply is None:
noreply = self.default_noreply
- return self._store_cmd(b'prepend', {key: value}, expire, noreply)[key]
+ return self._store_cmd(b'prepend', {key: value}, expire, noreply,
+ flags=flags)[key]
- def cas(self, key, value, cas, expire=0, noreply=False):
+ def cas(self, key, value, cas, expire=0, noreply=False, flags=None):
"""
The memcached "cas" command.
@@ -428,13 +456,16 @@
expire: optional int, number of seconds until the item is expired
from the cache, or zero for no expiry (the default).
noreply: optional bool, False to wait for the reply (the default).
+ flags: optional int, arbitrary bit field used for server-specific
+ flags
Returns:
If noreply is True, always returns True. Otherwise returns None if
the key didn't exist, False if it existed but had a different cas
value and True if it existed and was changed.
"""
- return self._store_cmd(b'cas', {key: value}, expire, noreply, cas)[key]
+ return self._store_cmd(b'cas', {key: value}, expire, noreply,
+ flags=flags, cas=cas)[key]
def get(self, key, default=None):
"""
@@ -571,7 +602,7 @@
value of the key, or None if the key wasn't found.
"""
key = self.check_key(key)
- cmd = b'incr ' + key + b' ' + six.text_type(value).encode('ascii')
+ cmd = b'incr ' + key + b' ' +
six.text_type(value).encode(self.encoding)
if noreply:
cmd += b' noreply'
cmd += b'\r\n'
@@ -596,7 +627,7 @@
value of the key, or None if the key wasn't found.
"""
key = self.check_key(key)
- cmd = b'decr ' + key + b' ' + six.text_type(value).encode('ascii')
+ cmd = b'decr ' + key + b' ' +
six.text_type(value).encode(self.encoding)
if noreply:
cmd += b' noreply'
cmd += b'\r\n'
@@ -625,7 +656,9 @@
if noreply is None:
noreply = self.default_noreply
key = self.check_key(key)
- cmd = b'touch ' + key + b' ' + six.text_type(expire).encode('ascii')
+ cmd = (
+ b'touch ' + key + b' ' +
six.text_type(expire).encode(self.encoding)
+ )
if noreply:
cmd += b' noreply'
cmd += b'\r\n'
@@ -706,7 +739,7 @@
"""
if noreply is None:
noreply = self.default_noreply
- cmd = b'flush_all ' + six.text_type(delay).encode('ascii')
+ cmd = b'flush_all ' + six.text_type(delay).encode(self.encoding)
if noreply:
cmd += b' noreply'
cmd += b'\r\n'
@@ -739,6 +772,31 @@
error = line[line.find(b' ') + 1:]
raise MemcacheServerError(error)
+ def _extract_value(self, expect_cas, line, buf, remapped_keys,
+ prefixed_keys):
+ """
+ This function is abstracted from _fetch_cmd to support different ways
+ of value extraction. In order to use this feature, _extract_value needs
+ to be overriden in the subclass.
+ """
+ if expect_cas:
+ _, key, flags, size, cas = line.split()
+ else:
+ try:
+ _, key, flags, size = line.split()
+ except Exception as e:
+ raise ValueError("Unable to parse line %s: %s" % (line, e))
+
+ buf, value = _readvalue(self.sock, buf, int(size))
+ key = remapped_keys[key]
+ if self.deserializer:
+ value = self.deserializer(key, value, int(flags))
+
+ if expect_cas:
+ return key, (value, cas), buf
+ else:
+ return key, value, buf
+
def _fetch_cmd(self, name, keys, expect_cas):
prefixed_keys = [self.check_key(k) for k in keys]
remapped_keys = dict(zip(prefixed_keys, keys))
@@ -760,25 +818,10 @@
if line == b'END' or line == b'OK':
return result
elif line.startswith(b'VALUE'):
- if expect_cas:
- _, key, flags, size, cas = line.split()
- else:
- try:
- _, key, flags, size = line.split()
- except Exception as e:
- raise ValueError("Unable to parse line %s: %s"
- % (line, str(e)))
-
- buf, value = _readvalue(self.sock, buf, int(size))
- key = remapped_keys[key]
-
- if self.deserializer:
- value = self.deserializer(key, value, int(flags))
-
- if expect_cas:
- result[key] = (value, cas)
- else:
- result[key] = value
+ key, value, buf = self._extract_value(expect_cas, line,
buf,
+ remapped_keys,
+ prefixed_keys)
+ result[key] = value
elif name == b'stats' and line.startswith(b'STAT'):
key_value = line.split()
result[key_value[1]] = key_value[2]
@@ -794,7 +837,7 @@
return {}
raise
- def _store_cmd(self, name, values, expire, noreply, cas=None):
+ def _store_cmd(self, name, values, expire, noreply, flags=None, cas=None):
cmds = []
keys = []
@@ -803,7 +846,7 @@
extra += b' ' + cas
if noreply:
extra += b' noreply'
- expire = six.text_type(expire).encode('ascii')
+ expire = six.text_type(expire).encode(self.encoding)
for key, data in six.iteritems(values):
# must be able to reliably map responses back to the original order
@@ -811,20 +854,26 @@
key = self.check_key(key)
if self.serializer:
- data, flags = self.serializer(key, data)
+ data, data_flags = self.serializer(key, data)
else:
- flags = 0
+ data_flags = 0
+
+ # If 'flags' was explicitly provided, it overrides the value
+ # returned by the serializer.
+ if flags is not None:
+ data_flags = flags
if not isinstance(data, six.binary_type):
try:
- data = six.text_type(data).encode('ascii')
+ data = six.text_type(data).encode(self.encoding)
except UnicodeEncodeError as e:
- raise MemcacheIllegalInputError(str(e))
+ raise MemcacheIllegalInputError(
+ "Data values must be binary-safe: %s" % e)
cmds.append(name + b' ' + key + b' ' +
- six.text_type(flags).encode('ascii') +
+ six.text_type(data_flags).encode(self.encoding) +
b' ' + expire +
- b' ' + six.text_type(len(data)).encode('ascii') +
+ b' ' + six.text_type(len(data)).encode(self.encoding) +
extra + b'\r\n' + data + b'\r\n')
if self.sock is None:
@@ -920,7 +969,8 @@
max_pool_size=None,
lock_generator=None,
default_noreply=True,
- allow_unicode_keys=False):
+ allow_unicode_keys=False,
+ encoding='ascii'):
self.server = server
self.serializer = serializer
self.deserializer = deserializer
@@ -941,6 +991,7 @@
after_remove=lambda client: client.close(),
max_size=max_pool_size,
lock_generator=lock_generator)
+ self.encoding = encoding
def check_key(self, key):
"""Checks key and add key_prefix."""
@@ -966,33 +1017,38 @@
def close(self):
self.client_pool.clear()
- def set(self, key, value, expire=0, noreply=None):
+ def set(self, key, value, expire=0, noreply=None, flags=None):
with self.client_pool.get_and_release(destroy_on_fail=True) as client:
- return client.set(key, value, expire=expire, noreply=noreply)
+ return client.set(key, value, expire=expire, noreply=noreply,
+ flags=flags)
- def set_many(self, values, expire=0, noreply=None):
+ def set_many(self, values, expire=0, noreply=None, flags=None):
with self.client_pool.get_and_release(destroy_on_fail=True) as client:
- failed = client.set_many(values, expire=expire, noreply=noreply)
+ failed = client.set_many(values, expire=expire, noreply=noreply,
+ flags=flags)
return failed
set_multi = set_many
- def replace(self, key, value, expire=0, noreply=None):
+ def replace(self, key, value, expire=0, noreply=None, flags=None):
with self.client_pool.get_and_release(destroy_on_fail=True) as client:
- return client.replace(key, value, expire=expire, noreply=noreply)
+ return client.replace(key, value, expire=expire, noreply=noreply,
+ flags=flags)
- def append(self, key, value, expire=0, noreply=None):
+ def append(self, key, value, expire=0, noreply=None, flags=None):
with self.client_pool.get_and_release(destroy_on_fail=True) as client:
- return client.append(key, value, expire=expire, noreply=noreply)
+ return client.append(key, value, expire=expire, noreply=noreply,
+ flags=flags)
- def prepend(self, key, value, expire=0, noreply=None):
+ def prepend(self, key, value, expire=0, noreply=None, flags=None):
with self.client_pool.get_and_release(destroy_on_fail=True) as client:
- return client.prepend(key, value, expire=expire, noreply=noreply)
+ return client.prepend(key, value, expire=expire, noreply=noreply,
+ flags=flags)
- def cas(self, key, value, cas, expire=0, noreply=False):
+ def cas(self, key, value, cas, expire=0, noreply=False, flags=None):
with self.client_pool.get_and_release(destroy_on_fail=True) as client:
return client.cas(key, value, cas,
- expire=expire, noreply=noreply)
+ expire=expire, noreply=noreply, flags=flags)
def get(self, key, default=None):
with self.client_pool.get_and_release(destroy_on_fail=True) as client:
@@ -1046,9 +1102,10 @@
delete_multi = delete_many
- def add(self, key, value, expire=0, noreply=None):
+ def add(self, key, value, expire=0, noreply=None, flags=None):
with self.client_pool.get_and_release(destroy_on_fail=True) as client:
- return client.add(key, value, expire=expire, noreply=noreply)
+ return client.add(key, value, expire=expire, noreply=noreply,
+ flags=flags)
def incr(self, key, value, noreply=False):
with self.client_pool.get_and_release(destroy_on_fail=True) as client:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/pymemcache/client/hash.py
new/pymemcache-2.2.2/pymemcache/client/hash.py
--- old/pymemcache-2.1.1/pymemcache/client/hash.py 2019-01-08
16:29:27.000000000 +0100
+++ new/pymemcache-2.2.2/pymemcache/client/hash.py 2019-06-08
00:30:13.000000000 +0200
@@ -33,7 +33,9 @@
dead_timeout=60,
use_pooling=False,
ignore_exc=False,
- allow_unicode_keys=False
+ allow_unicode_keys=False,
+ default_noreply=True,
+ encoding='ascii'
):
"""
Constructor.
@@ -54,6 +56,7 @@
attempts.
dead_timeout (float): Time in seconds before attempting to add a node
back in the pool.
+ encoding: optional str, controls data encoding (defaults to 'ascii').
Further arguments are interpreted as for :py:class:`.Client`
constructor.
@@ -81,6 +84,7 @@
'serializer': serializer,
'deserializer': deserializer,
'allow_unicode_keys': allow_unicode_keys,
+ 'default_noreply': default_noreply,
}
if use_pooling is True:
@@ -91,6 +95,7 @@
for server, port in servers:
self.add_server(server, port)
+ self.encoding = encoding
def add_server(self, server, port):
key = '%s:%s' % (server, port)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/pymemcache/test/test_client.py
new/pymemcache-2.2.2/pymemcache/test/test_client.py
--- old/pymemcache-2.1.1/pymemcache/test/test_client.py 2019-01-08
18:10:49.000000000 +0100
+++ new/pymemcache-2.2.2/pymemcache/test/test_client.py 2019-08-05
21:52:32.000000000 +0200
@@ -23,6 +23,7 @@
import mock
import socket
import unittest
+
import pytest
from pymemcache.client.base import PooledClient, Client
@@ -114,6 +115,13 @@
return getattr(socket, name)
+class CustomizedClient(Client):
+
+ def _extract_value(self, expect_cas, line, buf, remapped_keys,
+ prefixed_keys):
+ return b'key', b'value', b'END\r\n'
+
+
@pytest.mark.unit()
class ClientTestMixin(object):
def make_client(self, mock_socket_values, **kwargs):
@@ -126,16 +134,47 @@
setattr, client, "sock", sock))
return client
+ def make_customized_client(self, mock_socket_values, **kwargs):
+ client = CustomizedClient(None, **kwargs)
+ # mock out client._connect() rather than hard-settting client.sock to
+ # ensure methods are checking whether self.sock is None before
+ # attempting to use it
+ sock = MockSocket(list(mock_socket_values))
+ client._connect = mock.Mock(side_effect=functools.partial(
+ setattr, client, "sock", sock))
+ return client
+
def test_set_success(self):
client = self.make_client([b'STORED\r\n'])
result = client.set(b'key', b'value', noreply=False)
assert result is True
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.set(b'key', b'value', noreply=False)
+ assert result is True
+
+ # unit test for set operation with parameter flags
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.set(b'key', b'value', noreply=False, flags=0x00000030)
+ assert result is True
+
def test_set_future(self):
client = self.make_client([b'STORED\r\n'])
result = client.set(newbytes(b'key'), newbytes(b'value'),
noreply=False)
assert result is True
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.set(newbytes(b'key'), newbytes(b'value'),
noreply=False)
+ assert result is True
+
+ # unit test for set operation with parameter flags
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.set(newbytes(b'key'), newbytes(b'value'),
noreply=False,
+ flags=0x00000030)
+ assert result is True
+
def test_set_unicode_key(self):
client = self.make_client([b''])
@@ -196,26 +235,54 @@
result = client.set(b'key', b'value', noreply=True)
assert result is True
+ # unit test for encoding passed in __init__()
+ client = self.make_client([], encoding='utf-8')
+ result = client.set(b'key', b'value', noreply=True)
+ assert result is True
+
def test_set_many_success(self):
client = self.make_client([b'STORED\r\n'])
result = client.set_many({b'key': b'value'}, noreply=False)
assert result == []
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.set_many({b'key': b'value'}, noreply=False)
+ assert result == []
+
def test_set_multi_success(self):
# Should just map to set_many
client = self.make_client([b'STORED\r\n'])
result = client.set_multi({b'key': b'value'}, noreply=False)
assert result == []
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.set_multi({b'key': b'value'}, noreply=False)
+ assert result == []
+
def test_add_stored(self):
client = self.make_client([b'STORED\r', b'\n'])
result = client.add(b'key', b'value', noreply=False)
assert result is True
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r', b'\n'], encoding='utf-8')
+ result = client.add(b'key', b'value', noreply=False)
+ assert result is True
+
def test_add_not_stored(self):
client = self.make_client([b'STORED\r', b'\n',
b'NOT_', b'STOR', b'ED', b'\r\n'])
+ client.add(b'key', b'value', noreply=False)
result = client.add(b'key', b'value', noreply=False)
+ assert result is False
+
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r', b'\n',
+ b'NOT_', b'STOR', b'ED', b'\r\n'],
+ encoding='utf-8')
+ client.add(b'key', b'value', noreply=False)
result = client.add(b'key', b'value', noreply=False)
assert result is False
@@ -224,17 +291,36 @@
result = client.get(b'key')
assert result is None
+ # Unit test for customized client (override _extract_value)
+ client = self.make_customized_client([b'END\r\n'])
+ result = client.get(b'key')
+ assert result is None
+
def test_get_not_found_default(self):
client = self.make_client([b'END\r\n'])
result = client.get(b'key', default='foobar')
- assert result is 'foobar'
+ assert result == 'foobar'
+
+ # Unit test for customized client (override _extract_value)
+ client = self.make_customized_client([b'END\r\n'])
+ result = client.get(b'key', default='foobar')
+ assert result == 'foobar'
def test_get_found(self):
client = self.make_client([
b'STORED\r\n',
b'VALUE key 0 5\r\nvalue\r\nEND\r\n',
])
- result = client.set(b'key', b'value', noreply=False)
+ client.set(b'key', b'value', noreply=False)
+ result = client.get(b'key')
+ assert result == b'value'
+
+ # Unit test for customized client (override _extract_value)
+ client = self.make_customized_client([
+ b'STORED\r\n',
+ b'VALUE key 0 5\r\nvalue\r\nEND\r\n',
+ ])
+ client.set(b'key', b'value', noreply=False)
result = client.get(b'key')
assert result == b'value'
@@ -253,7 +339,7 @@
b'STORED\r\n',
b'VALUE key1 0 6\r\nvalue1\r\nEND\r\n',
])
- result = client.set(b'key1', b'value1', noreply=False)
+ client.set(b'key1', b'value1', noreply=False)
result = client.get_many([b'key1', b'key2'])
assert result == {b'key1': b'value1'}
@@ -264,8 +350,8 @@
b'VALUE key1 0 6\r\nvalue1\r\n',
b'VALUE key2 0 6\r\nvalue2\r\nEND\r\n',
])
- result = client.set(b'key1', b'value1', noreply=False)
- result = client.set(b'key2', b'value2', noreply=False)
+ client.set(b'key1', b'value1', noreply=False)
+ client.set(b'key2', b'value2', noreply=False)
result = client.get_many([b'key1', b'key2'])
assert result == {b'key1': b'value1', b'key2': b'value2'}
@@ -285,7 +371,7 @@
def test_delete_found(self):
client = self.make_client([b'STORED\r', b'\n', b'DELETED\r\n'])
- result = client.add(b'key', b'value', noreply=False)
+ client.add(b'key', b'value', noreply=False)
result = client.delete(b'key', noreply=False)
assert result is True
@@ -306,7 +392,7 @@
def test_delete_many_found(self):
client = self.make_client([b'STORED\r', b'\n', b'DELETED\r\n'])
- result = client.add(b'key', b'value', noreply=False)
+ client.add(b'key', b'value', noreply=False)
result = client.delete_many([b'key'], noreply=False)
assert result is True
@@ -316,7 +402,7 @@
b'DELETED\r\n',
b'NOT_FOUND\r\n'
])
- result = client.add(b'key', b'value', noreply=False)
+ client.add(b'key', b'value', noreply=False)
result = client.delete_many([b'key', b'key2'], noreply=False)
assert result is True
@@ -326,7 +412,7 @@
b'DELETED\r\n',
b'NOT_FOUND\r\n'
])
- result = client.add(b'key', b'value', noreply=False)
+ client.add(b'key', b'value', noreply=False)
result = client.delete_multi([b'key', b'key2'], noreply=False)
assert result is True
@@ -370,26 +456,51 @@
result = client.append(b'key', b'value', noreply=False)
assert result is True
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.append(b'key', b'value', noreply=False)
+ assert result is True
+
def test_prepend_stored(self):
client = self.make_client([b'STORED\r\n'])
result = client.prepend(b'key', b'value', noreply=False)
assert result is True
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.prepend(b'key', b'value', noreply=False)
+ assert result is True
+
def test_cas_stored(self):
client = self.make_client([b'STORED\r\n'])
result = client.cas(b'key', b'value', b'cas', noreply=False)
assert result is True
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.cas(b'key', b'value', b'cas', noreply=False)
+ assert result is True
+
def test_cas_exists(self):
client = self.make_client([b'EXISTS\r\n'])
result = client.cas(b'key', b'value', b'cas', noreply=False)
assert result is False
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'EXISTS\r\n'], encoding='utf-8')
+ result = client.cas(b'key', b'value', b'cas', noreply=False)
+ assert result is False
+
def test_cas_not_found(self):
client = self.make_client([b'NOT_FOUND\r\n'])
result = client.cas(b'key', b'value', b'cas', noreply=False)
assert result is None
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'NOT_FOUND\r\n'], encoding='utf-8')
+ result = client.cas(b'key', b'value', b'cas', noreply=False)
+ assert result is None
+
def test_cr_nl_boundaries(self):
client = self.make_client([b'VALUE key1 0 6\r',
b'\nvalue1\r\n'
@@ -538,11 +649,21 @@
result = client.replace(b'key', b'value', noreply=False)
assert result is True
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.replace(b'key', b'value', noreply=False)
+ assert result is True
+
def test_replace_not_stored(self):
client = self.make_client([b'NOT_STORED\r\n'])
result = client.replace(b'key', b'value', noreply=False)
assert result is False
+ # unit test for encoding passed in __init__
+ client = self.make_client([b'NOT_STORED\r\n'], encoding='utf-8')
+ result = client.replace(b'key', b'value', noreply=False)
+ assert result is False
+
def test_serialization(self):
def _ser(key, value):
return json.dumps(value), 0
@@ -553,6 +674,40 @@
b'set key 0 0 10 noreply\r\n{"c": "d"}\r\n'
]
+ def test_serialization_flags(self):
+ def _ser(key, value):
+ return value, 1 if isinstance(value, int) else 0
+
+ client = self.make_client(
+ [b'STORED\r\n', b'STORED\r\n'], serializer=_ser)
+ client.set_many(
+ collections.OrderedDict([(b'a', b's'), (b'b', 0)]), noreply=False)
+ assert client.sock.send_bufs == [
+ b'set a 0 0 1\r\ns\r\nset b 1 0 1\r\n0\r\n'
+ ]
+
+ def test_serialization_overridden_flags(self):
+ def _ser(key, value):
+ return value, 1 if isinstance(value, int) else 0
+
+ client = self.make_client(
+ [b'STORED\r\n', b'STORED\r\n'], serializer=_ser)
+ client.set_many(
+ collections.OrderedDict([(b'a', b's'), (b'b', 0)]),
+ noreply=False, flags=5)
+ assert client.sock.send_bufs == [
+ b'set a 5 0 1\r\ns\r\nset b 5 0 1\r\n0\r\n'
+ ]
+
+ def test_explicit_flags(self):
+ client = self.make_client([b'STORED\r\n', b'STORED\r\n'])
+ client.set_many(
+ collections.OrderedDict([(b'a', b's'), (b'b', 0)]),
+ noreply=False, flags=5)
+ assert client.sock.send_bufs == [
+ b'set a 5 0 1\r\ns\r\nset b 5 0 1\r\n0\r\n'
+ ]
+
def test_set_socket_handling(self):
client = self.make_client([b'STORED\r\n'])
result = client.set(b'key', b'value', noreply=False)
@@ -649,11 +804,31 @@
assert client.sock.closed is False
assert len(client.sock.send_bufs) == 1
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r\n'], encoding='utf-8')
+ result = client.set_many({b'key': b'value'}, noreply=False)
+ assert result == []
+ assert client.sock.closed is False
+ assert len(client.sock.send_bufs) == 1
+
def test_set_many_exception(self):
client = self.make_client([b'STORED\r\n', Exception('fail')])
def _set():
client.set_many({b'key': b'value', b'other': b'value'},
+ noreply=False)
+
+ with pytest.raises(Exception):
+ _set()
+
+ assert client.sock is None
+
+ # unit test for encoding passed in __init__()
+ client = self.make_client([b'STORED\r\n', Exception('fail')],
+ encoding='utf-8')
+
+ def _set():
+ client.set_many({b'key': b'value', b'other': b'value'},
noreply=False)
with pytest.raises(Exception):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/pymemcache/test/test_utils.py
new/pymemcache-2.2.2/pymemcache/test/test_utils.py
--- old/pymemcache-2.1.1/pymemcache/test/test_utils.py 2017-12-18
16:48:03.000000000 +0100
+++ new/pymemcache-2.2.2/pymemcache/test/test_utils.py 2019-05-07
19:37:31.000000000 +0200
@@ -14,6 +14,15 @@
@pytest.mark.unit()
+def test_get_set_unicide_key():
+ client = MockMemcacheClient()
+ assert client.get(u"hello") is None
+
+ client.set(b"hello", 12)
+ assert client.get(u"hello") == 12
+
+
[email protected]()
def test_get_set_non_ascii_value():
client = MockMemcacheClient()
assert client.get(b"hello") is None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/pymemcache/test/utils.py
new/pymemcache-2.2.2/pymemcache/test/utils.py
--- old/pymemcache-2.1.1/pymemcache/test/utils.py 2019-01-08
16:29:27.000000000 +0100
+++ new/pymemcache-2.2.2/pymemcache/test/utils.py 2019-07-05
19:11:21.000000000 +0200
@@ -27,7 +27,8 @@
no_delay=False,
ignore_exc=False,
default_noreply=True,
- allow_unicode_keys=False):
+ allow_unicode_keys=False,
+ encoding='ascii'):
self._contents = {}
@@ -41,11 +42,10 @@
self.timeout = timeout
self.no_delay = no_delay
self.ignore_exc = ignore_exc
+ self.encoding = encoding
def get(self, key, default=None):
if not self.allow_unicode_keys:
- if isinstance(key, six.text_type):
- raise MemcacheIllegalInputError(key)
if isinstance(key, six.string_types):
try:
if isinstance(key, bytes):
@@ -77,24 +77,20 @@
get_multi = get_many
- def set(self, key, value, expire=0, noreply=True):
+ def set(self, key, value, expire=0, noreply=True, flags=0):
if not self.allow_unicode_keys:
- if isinstance(key, six.text_type):
- raise MemcacheIllegalInputError(key)
if isinstance(key, six.string_types):
try:
if isinstance(key, bytes):
- key = key.decode().encode('ascii')
+ key = key.decode().encode()
else:
- key = key.encode('ascii')
+ key = key.encode(self.encoding)
except (UnicodeEncodeError, UnicodeDecodeError):
raise MemcacheIllegalInputError
- if isinstance(value, six.text_type):
- raise MemcacheIllegalInputError(value)
if (isinstance(value, six.string_types) and
not isinstance(value, six.binary_type)):
try:
- value = value.encode('ascii')
+ value = value.encode(self.encoding)
except (UnicodeEncodeError, UnicodeDecodeError):
raise MemcacheIllegalInputError
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/pymemcache.egg-info/PKG-INFO
new/pymemcache-2.2.2/pymemcache.egg-info/PKG-INFO
--- old/pymemcache-2.1.1/pymemcache.egg-info/PKG-INFO 2019-01-28
18:34:49.000000000 +0100
+++ new/pymemcache-2.2.2/pymemcache.egg-info/PKG-INFO 2019-08-06
21:07:47.000000000 +0200
@@ -1,8 +1,8 @@
-Metadata-Version: 1.1
+Metadata-Version: 2.1
Name: pymemcache
-Version: 2.1.1
-Summary: A comprehensive, fast, pure Python memcached client
-Home-page: https://github.com/Pinterest/pymemcache
+Version: 2.2.2
+Summary: "A comprehensive, fast, pure Python memcached client"
+Home-page: https://github.com/pinterest/pymemcache
Author: Charles Gordon
Author-email: [email protected]
License: Apache License 2.0
@@ -56,6 +56,13 @@
See the documentation here:
https://pymemcache.readthedocs.io/en/latest/
+ Django
+ ------
+
+ If you're planning on using pymemcache with Django, you might be
interested in
+ `django-pymemcache
<https://github.com/django-pymemcache/django-pymemcache>`_.
+ It provides a Django cache backend that is built on pymemcache.
+
Comparison with Other Libraries
===============================
@@ -133,8 +140,26 @@
Are you really excited about open-source? Or great software
engineering?
Pinterest is `hiring <https://careers.pinterest.com/>`_!
- Change Log
- ==========
+ Changelog
+ =========
+
+ New in version 2.2.2
+ --------------------
+ * Fix ``long_description`` string in Python packaging.
+
+ New in version 2.2.1
+ --------------------
+ * Fix ``flags`` when setting multiple differently-typed values at once.
+
+ New in version 2.2.0
+ --------------------
+ * Drop official support for Python 3.4.
+ * Use ``setup.cfg`` metadata instead ``setup.py`` config to generate
package.
+ * Add ``default_noreply`` parameter to ``HashClient``.
+ * Add ``encoding`` parameter to ``Client`` constructors (defaults to
``ascii``).
+ * Add ``flags`` parameter to write operation methods.
+ * Handle unicode key values in ``MockMemcacheClient`` correctly.
+ * Improve ASCII encoding failure exception.
New in version 2.1.1
--------------------
@@ -193,8 +218,8 @@
New in version 1.4.0
--------------------
- * Unicode keys support. It is now possible to pass the flag
`allow_unicode_keys` when creating the clients, thanks @jogo!
- * Fixed a bug where PooledClient wasn't following `default_noreply`
arg set on init, thanks @kols!
+ * Unicode keys support. It is now possible to pass the flag
``allow_unicode_keys`` when creating the clients, thanks @jogo!
+ * Fixed a bug where PooledClient wasn't following ``default_noreply``
arg set on init, thanks @kols!
* Improved documentation
New in version 1.3.8
@@ -245,13 +270,14 @@
--------------------
* Introduced PooledClient a thread-safe pool of clients
+Keywords: memcache,client,database
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
-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 :: Implementation :: PyPy
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Topic :: Database
+Description-Content-Type: text/x-rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/setup.cfg
new/pymemcache-2.2.2/setup.cfg
--- old/pymemcache-2.1.1/setup.cfg 2019-01-28 18:34:49.000000000 +0100
+++ new/pymemcache-2.2.2/setup.cfg 2019-08-06 21:07:47.000000000 +0200
@@ -1,3 +1,31 @@
+[metadata]
+name = pymemcache
+version = attr: pymemcache.__version__
+author = Charles Gordon
+author_email = [email protected]
+description = "A comprehensive, fast, pure Python memcached client"
+long_description = file: README.rst, ChangeLog.rst
+long_description_content_type = text/x-rst
+license = Apache License 2.0
+url = https://github.com/pinterest/pymemcache
+keywords = memcache, client, database
+classifiers =
+ Programming Language :: Python
+ Programming Language :: Python :: 2.7
+ Programming Language :: Python :: 3.5
+ Programming Language :: Python :: 3.6
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: Implementation :: PyPy
+ License :: OSI Approved :: Apache Software License
+ Topic :: Database
+
+[options]
+setup_requires =
+ six
+install_requires =
+ six
+packages = find:
+
[bdist_wheel]
universal = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pymemcache-2.1.1/setup.py
new/pymemcache-2.2.2/setup.py
--- old/pymemcache-2.1.1/setup.py 2019-01-28 18:34:10.000000000 +0100
+++ new/pymemcache-2.2.2/setup.py 2019-02-22 00:25:57.000000000 +0100
@@ -1,46 +1,5 @@
#!/usr/bin/env python
-import os
-import re
+from setuptools import setup
-from setuptools import setup, find_packages
-
-
-def read(path):
- return open(os.path.join(os.path.dirname(__file__), path)).read()
-
-
-def read_version(path):
- match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", read(path), re.M)
- if match:
- return match.group(1)
- raise RuntimeError("Unable to find __version__ in %s." % path)
-
-
-readme = read('README.rst')
-changelog = read('ChangeLog.rst')
-version = read_version('pymemcache/__init__.py')
-
-setup(
- name='pymemcache',
- version=version,
- author='Charles Gordon',
- author_email='[email protected]',
- packages=find_packages(),
- install_requires=['six'],
- description='A comprehensive, fast, pure Python memcached client',
- long_description=readme + '\n' + changelog,
- license='Apache License 2.0',
- url='https://github.com/Pinterest/pymemcache',
- classifiers=[
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: Implementation :: PyPy',
- 'License :: OSI Approved :: Apache Software License',
- 'Topic :: Database',
- ],
-)
+setup()