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 <tchva...@suse.com>
+
+- 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: char...@pinterest.com
 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
+
+
+@pytest.mark.unit()
 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: char...@pinterest.com
 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 = char...@pinterest.com
+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='char...@pinterest.com',
-    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()


Reply via email to