python-memcached-1.53/0000755002342000234200000000000012154412340013277 5ustar jafojafopython-memcached-1.53/Makefile0000664002342000234200000000020012154412330014730 0ustar jafojafotest: python memcache.py ( cd tests; make ) clean: rm -f memcache.pyc memcache.py.orig push: bzr push lp:python-memcached python-memcached-1.53/README.md0000664002342000234200000000124712154412330014563 0ustar jafojafoThis software is a 100% Python interface to the memcached memory cache daemon. It is the client side software which allows storing values in one or more, possibly remote, memcached servers. Search google for memcached for more information. This package was originally written by Evan Martin of Danga. Please do not contact Evan about maintenance. Sean Reifschneider of tummy.com, ltd. has taken over maintenance of it. Please report issues and submit code changes to the github repository at: https://github.com/linsomniac/python-memcached For changes prior to 2013-03-26, see the old Launchpad repository at: Historic issues: https://launchpad.net/python-memcached python-memcached-1.53/setup.py0000664002342000234200000000165512154412330015021 0ustar jafojafo#!/usr/bin/env python from setuptools import setup import memcache setup(name="python-memcached", version=memcache.__version__, description="Pure python memcached client", long_description=open("README.md").read(), author="Evan Martin", author_email="martine@danga.com", maintainer="Sean Reifschneider", maintainer_email="jafo@tummy.com", url="http://www.tummy.com/Community/software/python-memcached/", download_url="ftp://ftp.tummy.com/pub/python-memcached/", py_modules=["memcache"], classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Python Software Foundation License", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules", ]) python-memcached-1.53/PKG-INFO0000664002342000234200000000053412154412330014377 0ustar jafojafoMetadata-Version: 1.0 Name: python-memcached Version: 1.53 Summary: A Python memcached client library. Home-page: http://www.tummy.com/Community/software/python-memcached/ Author: Sean Reifschneider Author-email: jafo-memcached@tummy.com License: Python Software Foundation License Description: A Python memcached client library. Platform: UNKNOWN python-memcached-1.53/PSF.LICENSE0000664002342000234200000007062312154412330014744 0ustar jafojafoPYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -------------------------------------------- 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python. 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 ------------------------------------------- BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual or Organization ("Licensee") accessing and otherwise using this software in source or binary form and its associated documentation ("the Software"). 2. Subject to the terms and conditions of this BeOpen Python License Agreement, BeOpen hereby grants Licensee a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use the Software alone or in any derivative version, provided, however, that the BeOpen Python License is retained in the Software, alone or in any derivative version prepared by Licensee. 3. BeOpen is making the Software available to Licensee on an "AS IS" basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 5. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 6. This License Agreement shall be governed by and interpreted in all respects by the law of the State of California, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote products or services of Licensee, or any third party. As an exception, the "BeOpen Python" logos available at http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page. 7. By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions of this License Agreement. CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 --------------------------------------- 1. This LICENSE AGREEMENT is between the Corporation for National Research Initiatives, having an office at 1895 Preston White Drive, Reston, VA 20191 ("CNRI"), and the Individual or Organization ("Licensee") accessing and otherwise using Python 1.6.1 software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, CNRI hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6.1 alone or in any derivative version, provided, however, that CNRI's License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) 1995-2001 Corporation for National Research Initiatives; All Rights Reserved" are retained in Python 1.6.1 alone or in any derivative version prepared by Licensee. Alternately, in lieu of CNRI's License Agreement, Licensee may substitute the following text (omitting the quotes): "Python 1.6.1 is made available subject to the terms and conditions in CNRI's License Agreement. This Agreement together with Python 1.6.1 may be located on the Internet using the following unique, persistent identifier (known as a handle): 1895.22/1013. This Agreement may also be obtained from a proxy server on the Internet using the following URL: http://hdl.handle.net/1895.22/1013". 3. In the event Licensee prepares a derivative work that is based on or incorporates Python 1.6.1 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 1.6.1. 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. This License Agreement shall be governed by the federal intellectual property law of the United States, including without limitation the federal copyright law, and, to the extent such U.S. federal law does not apply, by the law of the Commonwealth of Virginia, excluding Virginia's conflict of law provisions. Notwithstanding the foregoing, with regard to derivative works based on Python 1.6.1 that incorporate non-separable material that was previously distributed under the GNU General Public License (GPL), the law of the Commonwealth of Virginia shall govern this License Agreement only as to issues arising under or with respect to Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between CNRI and Licensee. This License Agreement does not grant permission to use CNRI trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By clicking on the "ACCEPT" button where indicated, or by copying, installing or otherwise using Python 1.6.1, Licensee agrees to be bound by the terms and conditions of this License Agreement. ACCEPT CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 -------------------------------------------------- Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. This copy of Python includes a copy of bzip2, which is licensed under the following terms: This program, "bzip2", the associated library "libbzip2", and all documentation, are copyright (C) 1996-2005 Julian R Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Julian Seward, Cambridge, UK. jseward@acm.org bzip2/libbzip2 version 1.0.3 of 15 February 2005 This copy of Python includes a copy of db, which is licensed under the following terms: /*- * $Id: LICENSE,v 12.1 2005/06/16 20:20:10 bostic Exp $ */ The following is the license that applies to this copy of the Berkeley DB software. For a license to use the Berkeley DB software under conditions other than those described here, or to purchase support for this software, please contact Sleepycat Software by email at info@sleepycat.com, or on the Web at http://www.sleepycat.com. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= /* * Copyright (c) 1990-2005 * Sleepycat Software. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Redistributions in any form must be accompanied by information on * how to obtain complete source code for the DB software and any * accompanying software that uses the DB software. The source code * must either be included in the distribution or be available for no * more than the cost of distribution plus a nominal fee, and must be * freely redistributable under reasonable conditions. For an * executable file, complete source code means the source code for all * modules it contains. It does not include source code for modules or * files that typically accompany the major components of the operating * system on which the executable file runs. * * THIS SOFTWARE IS PROVIDED BY SLEEPYCAT SOFTWARE ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL SLEEPYCAT SOFTWARE * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1990, 1993, 1994, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 1995, 1996 * The President and Fellows of Harvard University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY HARVARD AND ITS CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HARVARD OR ITS CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ This copy of Python includes a copy of openssl, which is licensed under the following terms: LICENSE ISSUES ============== The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the OpenSSL License and the original SSLeay license apply to the toolkit. See below for the actual license texts. Actually both licenses are BSD-style Open Source licenses. In case of any license issues related to OpenSSL please contact openssl-core@openssl.org. OpenSSL License --------------- /* ==================================================================== * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ Original SSLeay License ----------------------- /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ This copy of Python includes a copy of tcl, which is licensed under the following terms: This software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState Corporation and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. This copy of Python includes a copy of tk, which is licensed under the following terms: This software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. python-memcached-1.53/setup.cfg0000664002342000234200000000015012154412330015115 0ustar jafojafo[bdist_rpm] release = 1 packager = Sean Reifschneider requires = python-memcached python-memcached-1.53/tests/0000775002342000234200000000000012154412330014442 5ustar jafojafopython-memcached-1.53/tests/Makefile0000664002342000234200000000020012154412330016072 0ustar jafojafoTESTS = $(wildcard test_*.py) test: @- $(foreach TEST,$(TESTS), \ echo === Running test: $(TEST); \ python $(TEST); \ ) python-memcached-1.53/tests/test_setmulti.py0000664002342000234200000000336312154412330017726 0ustar jafojafo#!/usr/bin/env python # # Tests for set_multi. # #=============== # This is based on a skeleton test file, more information at: # # https://github.com/linsomniac/python-unittest-skeleton import unittest import sys sys.path.append('..') import memcache import socket DEBUG = False class test_Memcached_Set_Multi(unittest.TestCase): def setUp(self): RECV_CHUNKS = ['chunk1'] class FakeSocket(object): def __init__(self, *args): if DEBUG: print 'FakeSocket{0!r}'.format(args) self._recv_chunks = list(RECV_CHUNKS) def connect(self, *args): if DEBUG: print 'FakeSocket.connect{0!r}'.format(args) def sendall(self, *args): if DEBUG: print 'FakeSocket.sendall{0!r}'.format(args) def recv(self, *args): if self._recv_chunks: data = self._recv_chunks.pop(0) else: data = '' if DEBUG: print 'FakeSocket.recv{0!r} -> {1!r}'.format(args, data) return data def close(self): if DEBUG: print 'FakeSocket.close()' self.old_socket = socket.socket socket.socket = FakeSocket def tearDown(self): socket.socket = self.old_socket def test_Socket_Disconnect(self): client = memcache.Client(['memcached'], debug=True) mapping = {'foo': 'FOO', 'bar': 'BAR'} bad_keys = client.set_multi(mapping) self.assertEqual(sorted(bad_keys), ['bar', 'foo']) if DEBUG: print 'set_multi({0!r}) -> {1!r}'.format(mapping, bad_keys) unittest.main() python-memcached-1.53/memcache.py0000664002342000234200000014623712154412333015434 0ustar jafojafo#!/usr/bin/env python """ client module for memcached (memory cache daemon) Overview ======== See U{the MemCached homepage} for more about memcached. Usage summary ============= This should give you a feel for how this module operates:: import memcache mc = memcache.Client(['127.0.0.1:11211'], debug=0) mc.set("some_key", "Some value") value = mc.get("some_key") mc.set("another_key", 3) mc.delete("another_key") mc.set("key", "1") # note that the key used for incr/decr must be a string. mc.incr("key") mc.decr("key") The standard way to use memcache with a database is like this:: key = derive_key(obj) obj = mc.get(key) if not obj: obj = backend_api.get(...) mc.set(key, obj) # we now have obj, and future passes through this code # will use the object from the cache. Detailed Documentation ====================== More detailed documentation is available in the L{Client} class. """ import sys import socket import time import os import re try: import cPickle as pickle except ImportError: import pickle from binascii import crc32 # zlib version is not cross-platform def cmemcache_hash(key): return((((crc32(key) & 0xffffffff) >> 16) & 0x7fff) or 1) serverHashFunction = cmemcache_hash def useOldServerHashFunction(): """Use the old python-memcache server hash function.""" global serverHashFunction serverHashFunction = crc32 try: from zlib import compress, decompress _supports_compress = True except ImportError: _supports_compress = False # quickly define a decompress just in case we recv compressed data. def decompress(val): raise _Error("received compressed data but I don't support compression (import error)") try: from cStringIO import StringIO except ImportError: from StringIO import StringIO valid_key_chars_re = re.compile('[\x21-\x7e\x80-\xff]+$') # Original author: Evan Martin of Danga Interactive __author__ = "Sean Reifschneider " __version__ = "1.53" __copyright__ = "Copyright (C) 2003 Danga Interactive" # http://en.wikipedia.org/wiki/Python_Software_Foundation_License __license__ = "Python Software Foundation License" SERVER_MAX_KEY_LENGTH = 250 # Storing values larger than 1MB requires recompiling memcached. If you do, # this value can be changed by doing "memcache.SERVER_MAX_VALUE_LENGTH = N" # after importing this module. SERVER_MAX_VALUE_LENGTH = 1024*1024 class _Error(Exception): pass class _ConnectionDeadError(Exception): pass try: # Only exists in Python 2.4+ from threading import local except ImportError: # TODO: add the pure-python local implementation class local(object): pass _DEAD_RETRY = 30 # number of seconds before retrying a dead server. _SOCKET_TIMEOUT = 3 # number of seconds before sockets timeout. class Client(local): """ Object representing a pool of memcache servers. See L{memcache} for an overview. In all cases where a key is used, the key can be either: 1. A simple hashable type (string, integer, etc.). 2. A tuple of C{(hashvalue, key)}. This is useful if you want to avoid making this module calculate a hash value. You may prefer, for example, to keep all of a given user's objects on the same memcache server, so you could use the user's unique id as the hash value. @group Setup: __init__, set_servers, forget_dead_hosts, disconnect_all, debuglog @group Insertion: set, add, replace, set_multi @group Retrieval: get, get_multi @group Integers: incr, decr @group Removal: delete, delete_multi @sort: __init__, set_servers, forget_dead_hosts, disconnect_all, debuglog,\ set, set_multi, add, replace, get, get_multi, incr, decr, delete, delete_multi """ _FLAG_PICKLE = 1<<0 _FLAG_INTEGER = 1<<1 _FLAG_LONG = 1<<2 _FLAG_COMPRESSED = 1<<3 _SERVER_RETRIES = 10 # how many times to try finding a free server. # exceptions for Client class MemcachedKeyError(Exception): pass class MemcachedKeyLengthError(MemcachedKeyError): pass class MemcachedKeyCharacterError(MemcachedKeyError): pass class MemcachedKeyNoneError(MemcachedKeyError): pass class MemcachedKeyTypeError(MemcachedKeyError): pass class MemcachedStringEncodingError(Exception): pass def __init__(self, servers, debug=0, pickleProtocol=0, pickler=pickle.Pickler, unpickler=pickle.Unpickler, pload=None, pid=None, server_max_key_length=SERVER_MAX_KEY_LENGTH, server_max_value_length=SERVER_MAX_VALUE_LENGTH, dead_retry=_DEAD_RETRY, socket_timeout=_SOCKET_TIMEOUT, cache_cas = False, flush_on_reconnect=0, check_keys=True): """ Create a new Client object with the given list of servers. @param servers: C{servers} is passed to L{set_servers}. @param debug: whether to display error messages when a server can't be contacted. @param pickleProtocol: number to mandate protocol used by (c)Pickle. @param pickler: optional override of default Pickler to allow subclassing. @param unpickler: optional override of default Unpickler to allow subclassing. @param pload: optional persistent_load function to call on pickle loading. Useful for cPickle since subclassing isn't allowed. @param pid: optional persistent_id function to call on pickle storing. Useful for cPickle since subclassing isn't allowed. @param dead_retry: number of seconds before retrying a blacklisted server. Default to 30 s. @param socket_timeout: timeout in seconds for all calls to a server. Defaults to 3 seconds. @param cache_cas: (default False) If true, cas operations will be cached. WARNING: This cache is not expired internally, if you have a long-running process you will need to expire it manually via client.reset_cas(), or the cache can grow unlimited. @param server_max_key_length: (default SERVER_MAX_KEY_LENGTH) Data that is larger than this will not be sent to the server. @param server_max_value_length: (default SERVER_MAX_VALUE_LENGTH) Data that is larger than this will not be sent to the server. @param flush_on_reconnect: optional flag which prevents a scenario that can cause stale data to be read: If there's more than one memcached server and the connection to one is interrupted, keys that mapped to that server will get reassigned to another. If the first server comes back, those keys will map to it again. If it still has its data, get()s can read stale data that was overwritten on another server. This flag is off by default for backwards compatibility. @param check_keys: (default True) If True, the key is checked to ensure it is the correct length and composed of the right characters. """ local.__init__(self) self.debug = debug self.dead_retry = dead_retry self.socket_timeout = socket_timeout self.flush_on_reconnect = flush_on_reconnect self.set_servers(servers) self.stats = {} self.cache_cas = cache_cas self.reset_cas() self.do_check_key = check_keys # Allow users to modify pickling/unpickling behavior self.pickleProtocol = pickleProtocol self.pickler = pickler self.unpickler = unpickler self.persistent_load = pload self.persistent_id = pid self.server_max_key_length = server_max_key_length self.server_max_value_length = server_max_value_length # figure out the pickler style file = StringIO() try: pickler = self.pickler(file, protocol = self.pickleProtocol) self.picklerIsKeyword = True except TypeError: self.picklerIsKeyword = False def reset_cas(self): """ Reset the cas cache. This is only used if the Client() object was created with "cache_cas=True". If used, this cache does not expire internally, so it can grow unbounded if you do not clear it yourself. """ self.cas_ids = {} def set_servers(self, servers): """ Set the pool of servers used by this client. @param servers: an array of servers. Servers can be passed in two forms: 1. Strings of the form C{"host:port"}, which implies a default weight of 1. 2. Tuples of the form C{("host:port", weight)}, where C{weight} is an integer weight value. """ self.servers = [_Host(s, self.debug, dead_retry=self.dead_retry, socket_timeout=self.socket_timeout, flush_on_reconnect=self.flush_on_reconnect) for s in servers] self._init_buckets() def get_stats(self, stat_args = None): '''Get statistics from each of the servers. @param stat_args: Additional arguments to pass to the memcache "stats" command. @return: A list of tuples ( server_identifier, stats_dictionary ). The dictionary contains a number of name/value pairs specifying the name of the status field and the string value associated with it. The values are not converted from strings. ''' data = [] for s in self.servers: if not s.connect(): continue if s.family == socket.AF_INET: name = '%s:%s (%s)' % ( s.ip, s.port, s.weight ) elif s.family == socket.AF_INET6: name = '[%s]:%s (%s)' % ( s.ip, s.port, s.weight ) else: name = 'unix:%s (%s)' % ( s.address, s.weight ) if not stat_args: s.send_cmd('stats') else: s.send_cmd('stats ' + stat_args) serverData = {} data.append(( name, serverData )) readline = s.readline while 1: line = readline() if not line or line.strip() == 'END': break stats = line.split(' ', 2) serverData[stats[1]] = stats[2] return(data) def get_slabs(self): data = [] for s in self.servers: if not s.connect(): continue if s.family == socket.AF_INET: name = '%s:%s (%s)' % ( s.ip, s.port, s.weight ) elif s.family == socket.AF_INET6: name = '[%s]:%s (%s)' % ( s.ip, s.port, s.weight ) else: name = 'unix:%s (%s)' % ( s.address, s.weight ) serverData = {} data.append(( name, serverData )) s.send_cmd('stats items') readline = s.readline while 1: line = readline() if not line or line.strip() == 'END': break item = line.split(' ', 2) #0 = STAT, 1 = ITEM, 2 = Value slab = item[1].split(':', 2) #0 = items, 1 = Slab #, 2 = Name if slab[1] not in serverData: serverData[slab[1]] = {} serverData[slab[1]][slab[2]] = item[2] return data def flush_all(self): """Expire all data in memcache servers that are reachable.""" for s in self.servers: if not s.connect(): continue s.flush() def debuglog(self, str): if self.debug: sys.stderr.write("MemCached: %s\n" % str) def _statlog(self, func): if func not in self.stats: self.stats[func] = 1 else: self.stats[func] += 1 def forget_dead_hosts(self): """ Reset every host in the pool to an "alive" state. """ for s in self.servers: s.deaduntil = 0 def _init_buckets(self): self.buckets = [] for server in self.servers: for i in range(server.weight): self.buckets.append(server) def _get_server(self, key): if isinstance(key, tuple): serverhash, key = key else: serverhash = serverHashFunction(key) for i in range(Client._SERVER_RETRIES): server = self.buckets[serverhash % len(self.buckets)] if server.connect(): #print "(using server %s)" % server, return server, key serverhash = serverHashFunction(str(serverhash) + str(i)) return None, None def disconnect_all(self): for s in self.servers: s.close_socket() def delete_multi(self, keys, time=0, key_prefix=''): ''' Delete multiple keys in the memcache doing just one query. >>> notset_keys = mc.set_multi({'key1' : 'val1', 'key2' : 'val2'}) >>> mc.get_multi(['key1', 'key2']) == {'key1' : 'val1', 'key2' : 'val2'} 1 >>> mc.delete_multi(['key1', 'key2']) 1 >>> mc.get_multi(['key1', 'key2']) == {} 1 This method is recommended over iterated regular L{delete}s as it reduces total latency, since your app doesn't have to wait for each round-trip of L{delete} before sending the next one. @param keys: An iterable of keys to clear @param time: number of seconds any subsequent set / update commands should fail. Defaults to 0 for no delay. @param key_prefix: Optional string to prepend to each key when sending to memcache. See docs for L{get_multi} and L{set_multi}. @return: 1 if no failure in communication with any memcacheds. @rtype: int ''' self._statlog('delete_multi') server_keys, prefixed_to_orig_key = self._map_and_prefix_keys(keys, key_prefix) # send out all requests on each server before reading anything dead_servers = [] rc = 1 for server in server_keys.iterkeys(): bigcmd = [] write = bigcmd.append if time != None: for key in server_keys[server]: # These are mangled keys write("delete %s %d\r\n" % (key, time)) else: for key in server_keys[server]: # These are mangled keys write("delete %s\r\n" % key) try: server.send_cmds(''.join(bigcmd)) except socket.error, msg: rc = 0 if isinstance(msg, tuple): msg = msg[1] server.mark_dead(msg) dead_servers.append(server) # if any servers died on the way, don't expect them to respond. for server in dead_servers: del server_keys[server] for server, keys in server_keys.iteritems(): try: for key in keys: server.expect("DELETED") except socket.error, msg: if isinstance(msg, tuple): msg = msg[1] server.mark_dead(msg) rc = 0 return rc def delete(self, key, time=0): '''Deletes a key from the memcache. @return: Nonzero on success. @param time: number of seconds any subsequent set / update commands should fail. Defaults to None for no delay. @rtype: int ''' if self.do_check_key: self.check_key(key) server, key = self._get_server(key) if not server: return 0 self._statlog('delete') if time != None and time != 0: cmd = "delete %s %d" % (key, time) else: cmd = "delete %s" % key try: server.send_cmd(cmd) line = server.readline() if line and line.strip() in ['DELETED', 'NOT_FOUND']: return 1 self.debuglog('Delete expected DELETED or NOT_FOUND, got: %s' % repr(line)) except socket.error, msg: if isinstance(msg, tuple): msg = msg[1] server.mark_dead(msg) return 0 def incr(self, key, delta=1): """ Sends a command to the server to atomically increment the value for C{key} by C{delta}, or by 1 if C{delta} is unspecified. Returns None if C{key} doesn't exist on server, otherwise it returns the new value after incrementing. Note that the value for C{key} must already exist in the memcache, and it must be the string representation of an integer. >>> mc.set("counter", "20") # returns 1, indicating success 1 >>> mc.incr("counter") 21 >>> mc.incr("counter") 22 Overflow on server is not checked. Be aware of values approaching 2**32. See L{decr}. @param delta: Integer amount to increment by (should be zero or greater). @return: New value after incrementing. @rtype: int """ return self._incrdecr("incr", key, delta) def decr(self, key, delta=1): """ Like L{incr}, but decrements. Unlike L{incr}, underflow is checked and new values are capped at 0. If server value is 1, a decrement of 2 returns 0, not -1. @param delta: Integer amount to decrement by (should be zero or greater). @return: New value after decrementing or None on error. @rtype: int """ return self._incrdecr("decr", key, delta) def _incrdecr(self, cmd, key, delta): if self.do_check_key: self.check_key(key) server, key = self._get_server(key) if not server: return None self._statlog(cmd) cmd = "%s %s %d" % (cmd, key, delta) try: server.send_cmd(cmd) line = server.readline() if line == None or line.strip() =='NOT_FOUND': return None return int(line) except socket.error, msg: if isinstance(msg, tuple): msg = msg[1] server.mark_dead(msg) return None def add(self, key, val, time = 0, min_compress_len = 0): ''' Add new key with value. Like L{set}, but only stores in memcache if the key doesn't already exist. @return: Nonzero on success. @rtype: int ''' return self._set("add", key, val, time, min_compress_len) def append(self, key, val, time=0, min_compress_len=0): '''Append the value to the end of the existing key's value. Only stores in memcache if key already exists. Also see L{prepend}. @return: Nonzero on success. @rtype: int ''' return self._set("append", key, val, time, min_compress_len) def prepend(self, key, val, time=0, min_compress_len=0): '''Prepend the value to the beginning of the existing key's value. Only stores in memcache if key already exists. Also see L{append}. @return: Nonzero on success. @rtype: int ''' return self._set("prepend", key, val, time, min_compress_len) def replace(self, key, val, time=0, min_compress_len=0): '''Replace existing key with value. Like L{set}, but only stores in memcache if the key already exists. The opposite of L{add}. @return: Nonzero on success. @rtype: int ''' return self._set("replace", key, val, time, min_compress_len) def set(self, key, val, time=0, min_compress_len=0): '''Unconditionally sets a key to a given value in the memcache. The C{key} can optionally be an tuple, with the first element being the server hash value and the second being the key. If you want to avoid making this module calculate a hash value. You may prefer, for example, to keep all of a given user's objects on the same memcache server, so you could use the user's unique id as the hash value. @return: Nonzero on success. @rtype: int @param time: Tells memcached the time which this value should expire, either as a delta number of seconds, or an absolute unix time-since-the-epoch value. See the memcached protocol docs section "Storage Commands" for more info on . We default to 0 == cache forever. @param min_compress_len: The threshold length to kick in auto-compression of the value using the zlib.compress() routine. If the value being cached is a string, then the length of the string is measured, else if the value is an object, then the length of the pickle result is measured. If the resulting attempt at compression yeilds a larger string than the input, then it is discarded. For backwards compatability, this parameter defaults to 0, indicating don't ever try to compress. ''' return self._set("set", key, val, time, min_compress_len) def cas(self, key, val, time=0, min_compress_len=0): '''Sets a key to a given value in the memcache if it hasn't been altered since last fetched. (See L{gets}). The C{key} can optionally be an tuple, with the first element being the server hash value and the second being the key. If you want to avoid making this module calculate a hash value. You may prefer, for example, to keep all of a given user's objects on the same memcache server, so you could use the user's unique id as the hash value. @return: Nonzero on success. @rtype: int @param time: Tells memcached the time which this value should expire, either as a delta number of seconds, or an absolute unix time-since-the-epoch value. See the memcached protocol docs section "Storage Commands" for more info on . We default to 0 == cache forever. @param min_compress_len: The threshold length to kick in auto-compression of the value using the zlib.compress() routine. If the value being cached is a string, then the length of the string is measured, else if the value is an object, then the length of the pickle result is measured. If the resulting attempt at compression yeilds a larger string than the input, then it is discarded. For backwards compatability, this parameter defaults to 0, indicating don't ever try to compress. ''' return self._set("cas", key, val, time, min_compress_len) def _map_and_prefix_keys(self, key_iterable, key_prefix): """Compute the mapping of server (_Host instance) -> list of keys to stuff onto that server, as well as the mapping of prefixed key -> original key. """ # Check it just once ... key_extra_len=len(key_prefix) if key_prefix and self.do_check_key: self.check_key(key_prefix) # server (_Host) -> list of unprefixed server keys in mapping server_keys = {} prefixed_to_orig_key = {} # build up a list for each server of all the keys we want. for orig_key in key_iterable: if isinstance(orig_key, tuple): # Tuple of hashvalue, key ala _get_server(). Caller is essentially telling us what server to stuff this on. # Ensure call to _get_server gets a Tuple as well. str_orig_key = str(orig_key[1]) server, key = self._get_server((orig_key[0], key_prefix + str_orig_key)) # Gotta pre-mangle key before hashing to a server. Returns the mangled key. else: str_orig_key = str(orig_key) # set_multi supports int / long keys. server, key = self._get_server(key_prefix + str_orig_key) # Now check to make sure key length is proper ... if self.do_check_key: self.check_key(str_orig_key, key_extra_len=key_extra_len) if not server: continue if server not in server_keys: server_keys[server] = [] server_keys[server].append(key) prefixed_to_orig_key[key] = orig_key return (server_keys, prefixed_to_orig_key) def set_multi(self, mapping, time=0, key_prefix='', min_compress_len=0): ''' Sets multiple keys in the memcache doing just one query. >>> notset_keys = mc.set_multi({'key1' : 'val1', 'key2' : 'val2'}) >>> mc.get_multi(['key1', 'key2']) == {'key1' : 'val1', 'key2' : 'val2'} 1 This method is recommended over regular L{set} as it lowers the number of total packets flying around your network, reducing total latency, since your app doesn't have to wait for each round-trip of L{set} before sending the next one. @param mapping: A dict of key/value pairs to set. @param time: Tells memcached the time which this value should expire, either as a delta number of seconds, or an absolute unix time-since-the-epoch value. See the memcached protocol docs section "Storage Commands" for more info on . We default to 0 == cache forever. @param key_prefix: Optional string to prepend to each key when sending to memcache. Allows you to efficiently stuff these keys into a pseudo-namespace in memcache: >>> notset_keys = mc.set_multi( ... {'key1' : 'val1', 'key2' : 'val2'}, key_prefix='subspace_') >>> len(notset_keys) == 0 True >>> mc.get_multi(['subspace_key1', 'subspace_key2']) == {'subspace_key1' : 'val1', 'subspace_key2' : 'val2'} True Causes key 'subspace_key1' and 'subspace_key2' to be set. Useful in conjunction with a higher-level layer which applies namespaces to data in memcache. In this case, the return result would be the list of notset original keys, prefix not applied. @param min_compress_len: The threshold length to kick in auto-compression of the value using the zlib.compress() routine. If the value being cached is a string, then the length of the string is measured, else if the value is an object, then the length of the pickle result is measured. If the resulting attempt at compression yeilds a larger string than the input, then it is discarded. For backwards compatability, this parameter defaults to 0, indicating don't ever try to compress. @return: List of keys which failed to be stored [ memcache out of memory, etc. ]. @rtype: list ''' self._statlog('set_multi') server_keys, prefixed_to_orig_key = self._map_and_prefix_keys( mapping.iterkeys(), key_prefix) # send out all requests on each server before reading anything dead_servers = [] notstored = [] # original keys. for server in server_keys.iterkeys(): bigcmd = [] write = bigcmd.append try: for key in server_keys[server]: # These are mangled keys store_info = self._val_to_store_info( mapping[prefixed_to_orig_key[key]], min_compress_len) if store_info: write("set %s %d %d %d\r\n%s\r\n" % (key, store_info[0], time, store_info[1], store_info[2])) else: notstored.append(prefixed_to_orig_key[key]) server.send_cmds(''.join(bigcmd)) except socket.error, msg: if isinstance(msg, tuple): msg = msg[1] server.mark_dead(msg) dead_servers.append(server) # if any servers died on the way, don't expect them to respond. for server in dead_servers: del server_keys[server] # short-circuit if there are no servers, just return all keys if not server_keys: return(mapping.keys()) for server, keys in server_keys.iteritems(): try: for key in keys: if server.readline() == 'STORED': continue else: notstored.append(prefixed_to_orig_key[key]) #un-mangle. except (_Error, socket.error), msg: if isinstance(msg, tuple): msg = msg[1] server.mark_dead(msg) return notstored def _val_to_store_info(self, val, min_compress_len): """ Transform val to a storable representation, returning a tuple of the flags, the length of the new value, and the new value itself. """ flags = 0 if isinstance(val, str): pass elif isinstance(val, int): flags |= Client._FLAG_INTEGER val = "%d" % val # force no attempt to compress this silly string. min_compress_len = 0 elif isinstance(val, long): flags |= Client._FLAG_LONG val = "%d" % val # force no attempt to compress this silly string. min_compress_len = 0 else: flags |= Client._FLAG_PICKLE file = StringIO() if self.picklerIsKeyword: pickler = self.pickler(file, protocol = self.pickleProtocol) else: pickler = self.pickler(file, self.pickleProtocol) if self.persistent_id: pickler.persistent_id = self.persistent_id pickler.dump(val) val = file.getvalue() lv = len(val) # We should try to compress if min_compress_len > 0 and we could # import zlib and this string is longer than our min threshold. if min_compress_len and _supports_compress and lv > min_compress_len: comp_val = compress(val) # Only retain the result if the compression result is smaller # than the original. if len(comp_val) < lv: flags |= Client._FLAG_COMPRESSED val = comp_val # silently do not store if value length exceeds maximum if self.server_max_value_length != 0 and \ len(val) > self.server_max_value_length: return(0) return (flags, len(val), val) def _set(self, cmd, key, val, time, min_compress_len = 0): if self.do_check_key: self.check_key(key) server, key = self._get_server(key) if not server: return 0 def _unsafe_set(): self._statlog(cmd) store_info = self._val_to_store_info(val, min_compress_len) if not store_info: return(0) if cmd == 'cas': if key not in self.cas_ids: return self._set('set', key, val, time, min_compress_len) fullcmd = "%s %s %d %d %d %d\r\n%s" % ( cmd, key, store_info[0], time, store_info[1], self.cas_ids[key], store_info[2]) else: fullcmd = "%s %s %d %d %d\r\n%s" % ( cmd, key, store_info[0], time, store_info[1], store_info[2]) try: server.send_cmd(fullcmd) return(server.expect("STORED", raise_exception=True) == "STORED") except socket.error, msg: if isinstance(msg, tuple): msg = msg[1] server.mark_dead(msg) return 0 try: return _unsafe_set() except _ConnectionDeadError: # retry once try: if server._get_socket(): return _unsafe_set() except (_ConnectionDeadError, socket.error), msg: server.mark_dead(msg) return 0 def _get(self, cmd, key): if self.do_check_key: self.check_key(key) server, key = self._get_server(key) if not server: return None def _unsafe_get(): self._statlog(cmd) try: server.send_cmd("%s %s" % (cmd, key)) rkey = flags = rlen = cas_id = None if cmd == 'gets': rkey, flags, rlen, cas_id, = self._expect_cas_value(server, raise_exception=True) if rkey and self.cache_cas: self.cas_ids[rkey] = cas_id else: rkey, flags, rlen, = self._expectvalue(server, raise_exception=True) if not rkey: return None try: value = self._recv_value(server, flags, rlen) finally: server.expect("END", raise_exception=True) except (_Error, socket.error), msg: if isinstance(msg, tuple): msg = msg[1] server.mark_dead(msg) return None return value try: return _unsafe_get() except _ConnectionDeadError: # retry once try: if server.connect(): return _unsafe_get() return None except (_ConnectionDeadError, socket.error), msg: server.mark_dead(msg) return None def get(self, key): '''Retrieves a key from the memcache. @return: The value or None. ''' return self._get('get', key) def gets(self, key): '''Retrieves a key from the memcache. Used in conjunction with 'cas'. @return: The value or None. ''' return self._get('gets', key) def get_multi(self, keys, key_prefix=''): ''' Retrieves multiple keys from the memcache doing just one query. >>> success = mc.set("foo", "bar") >>> success = mc.set("baz", 42) >>> mc.get_multi(["foo", "baz", "foobar"]) == {"foo": "bar", "baz": 42} 1 >>> mc.set_multi({'k1' : 1, 'k2' : 2}, key_prefix='pfx_') == [] 1 This looks up keys 'pfx_k1', 'pfx_k2', ... . Returned dict will just have unprefixed keys 'k1', 'k2'. >>> mc.get_multi(['k1', 'k2', 'nonexist'], key_prefix='pfx_') == {'k1' : 1, 'k2' : 2} 1 get_mult [ and L{set_multi} ] can take str()-ables like ints / longs as keys too. Such as your db pri key fields. They're rotored through str() before being passed off to memcache, with or without the use of a key_prefix. In this mode, the key_prefix could be a table name, and the key itself a db primary key number. >>> mc.set_multi({42: 'douglass adams', 46 : 'and 2 just ahead of me'}, key_prefix='numkeys_') == [] 1 >>> mc.get_multi([46, 42], key_prefix='numkeys_') == {42: 'douglass adams', 46 : 'and 2 just ahead of me'} 1 This method is recommended over regular L{get} as it lowers the number of total packets flying around your network, reducing total latency, since your app doesn't have to wait for each round-trip of L{get} before sending the next one. See also L{set_multi}. @param keys: An array of keys. @param key_prefix: A string to prefix each key when we communicate with memcache. Facilitates pseudo-namespaces within memcache. Returned dictionary keys will not have this prefix. @return: A dictionary of key/value pairs that were available. If key_prefix was provided, the keys in the retured dictionary will not have it present. ''' self._statlog('get_multi') server_keys, prefixed_to_orig_key = self._map_and_prefix_keys(keys, key_prefix) # send out all requests on each server before reading anything dead_servers = [] for server in server_keys.iterkeys(): try: server.send_cmd("get %s" % " ".join(server_keys[server])) except socket.error, msg: if isinstance(msg, tuple): msg = msg[1] server.mark_dead(msg) dead_servers.append(server) # if any servers died on the way, don't expect them to respond. for server in dead_servers: del server_keys[server] retvals = {} for server in server_keys.iterkeys(): try: line = server.readline() while line and line != 'END': rkey, flags, rlen = self._expectvalue(server, line) # Bo Yang reports that this can sometimes be None if rkey is not None: val = self._recv_value(server, flags, rlen) retvals[prefixed_to_orig_key[rkey]] = val # un-prefix returned key. line = server.readline() except (_Error, socket.error), msg: if isinstance(msg, tuple): msg = msg[1] server.mark_dead(msg) return retvals def _expect_cas_value(self, server, line=None, raise_exception=False): if not line: line = server.readline(raise_exception) if line and line[:5] == 'VALUE': resp, rkey, flags, len, cas_id = line.split() return (rkey, int(flags), int(len), int(cas_id)) else: return (None, None, None, None) def _expectvalue(self, server, line=None, raise_exception=False): if not line: line = server.readline(raise_exception) if line and line[:5] == 'VALUE': resp, rkey, flags, len = line.split() flags = int(flags) rlen = int(len) return (rkey, flags, rlen) else: return (None, None, None) def _recv_value(self, server, flags, rlen): rlen += 2 # include \r\n buf = server.recv(rlen) if len(buf) != rlen: raise _Error("received %d bytes when expecting %d" % (len(buf), rlen)) if len(buf) == rlen: buf = buf[:-2] # strip \r\n if flags & Client._FLAG_COMPRESSED: buf = decompress(buf) if flags == 0 or flags == Client._FLAG_COMPRESSED: # Either a bare string or a compressed string now decompressed... val = buf elif flags & Client._FLAG_INTEGER: val = int(buf) elif flags & Client._FLAG_LONG: val = long(buf) elif flags & Client._FLAG_PICKLE: try: file = StringIO(buf) unpickler = self.unpickler(file) if self.persistent_load: unpickler.persistent_load = self.persistent_load val = unpickler.load() except Exception, e: self.debuglog('Pickle error: %s\n' % e) return None else: self.debuglog("unknown flags on get: %x\n" % flags) return val def check_key(self, key, key_extra_len=0): """Checks sanity of key. Fails if: Key length is > SERVER_MAX_KEY_LENGTH (Raises MemcachedKeyLength). Contains control characters (Raises MemcachedKeyCharacterError). Is not a string (Raises MemcachedStringEncodingError) Is an unicode string (Raises MemcachedStringEncodingError) Is not a string (Raises MemcachedKeyError) Is None (Raises MemcachedKeyError) """ if isinstance(key, tuple): key = key[1] if not key: raise Client.MemcachedKeyNoneError("Key is None") if isinstance(key, unicode): raise Client.MemcachedStringEncodingError( "Keys must be str()'s, not unicode. Convert your unicode " "strings using mystring.encode(charset)!") if not isinstance(key, str): raise Client.MemcachedKeyTypeError("Key must be str()'s") if isinstance(key, basestring): if self.server_max_key_length != 0 and \ len(key) + key_extra_len > self.server_max_key_length: raise Client.MemcachedKeyLengthError("Key length is > %s" % self.server_max_key_length) if not valid_key_chars_re.match(key): raise Client.MemcachedKeyCharacterError( "Control characters not allowed") class _Host(object): def __init__(self, host, debug=0, dead_retry=_DEAD_RETRY, socket_timeout=_SOCKET_TIMEOUT, flush_on_reconnect=0): self.dead_retry = dead_retry self.socket_timeout = socket_timeout self.debug = debug self.flush_on_reconnect = flush_on_reconnect if isinstance(host, tuple): host, self.weight = host else: self.weight = 1 # parse the connection string m = re.match(r'^(?Punix):(?P.*)$', host) if not m: m = re.match(r'^(?Pinet6):' r'\[(?P[^\[\]]+)\](:(?P[0-9]+))?$', host) if not m: m = re.match(r'^(?Pinet):' r'(?P[^:]+)(:(?P[0-9]+))?$', host) if not m: m = re.match(r'^(?P[^:]+)(:(?P[0-9]+))?$', host) if not m: raise ValueError('Unable to parse connection string: "%s"' % host) hostData = m.groupdict() if hostData.get('proto') == 'unix': self.family = socket.AF_UNIX self.address = hostData['path'] elif hostData.get('proto') == 'inet6': self.family = socket.AF_INET6 self.ip = hostData['host'] self.port = int(hostData.get('port') or 11211) self.address = ( self.ip, self.port ) else: self.family = socket.AF_INET self.ip = hostData['host'] self.port = int(hostData.get('port') or 11211) self.address = ( self.ip, self.port ) self.deaduntil = 0 self.socket = None self.flush_on_next_connect = 0 self.buffer = '' def debuglog(self, str): if self.debug: sys.stderr.write("MemCached: %s\n" % str) def _check_dead(self): if self.deaduntil and self.deaduntil > time.time(): return 1 self.deaduntil = 0 return 0 def connect(self): if self._get_socket(): return 1 return 0 def mark_dead(self, reason): self.debuglog("MemCache: %s: %s. Marking dead." % (self, reason)) self.deaduntil = time.time() + self.dead_retry if self.flush_on_reconnect: self.flush_on_next_connect = 1 self.close_socket() def _get_socket(self): if self._check_dead(): return None if self.socket: return self.socket s = socket.socket(self.family, socket.SOCK_STREAM) if hasattr(s, 'settimeout'): s.settimeout(self.socket_timeout) try: s.connect(self.address) except socket.timeout, msg: self.mark_dead("connect: %s" % msg) return None except socket.error, msg: if isinstance(msg, tuple): msg = msg[1] self.mark_dead("connect: %s" % msg[1]) return None self.socket = s self.buffer = '' if self.flush_on_next_connect: self.flush() self.flush_on_next_connect = 0 return s def close_socket(self): if self.socket: self.socket.close() self.socket = None def send_cmd(self, cmd): self.socket.sendall(cmd + '\r\n') def send_cmds(self, cmds): """ cmds already has trailing \r\n's applied """ self.socket.sendall(cmds) def readline(self, raise_exception=False): """Read a line and return it. If "raise_exception" is set, raise _ConnectionDeadError if the read fails, otherwise return an empty string. """ buf = self.buffer if self.socket: recv = self.socket.recv else: recv = lambda bufsize: '' while True: index = buf.find('\r\n') if index >= 0: break data = recv(4096) if not data: # connection close, let's kill it and raise self.mark_dead('connection closed in readline()') if raise_exception: raise _ConnectionDeadError() else: return '' buf += data self.buffer = buf[index+2:] return buf[:index] def expect(self, text, raise_exception=False): line = self.readline(raise_exception) if line != text: self.debuglog("while expecting '%s', got unexpected response '%s'" % (text, line)) return line def recv(self, rlen): self_socket_recv = self.socket.recv buf = self.buffer while len(buf) < rlen: foo = self_socket_recv(max(rlen - len(buf), 4096)) buf += foo if not foo: raise _Error( 'Read %d bytes, expecting %d, ' 'read returned 0 length bytes' % ( len(buf), rlen )) self.buffer = buf[rlen:] return buf[:rlen] def flush(self): self.send_cmd('flush_all') self.expect('OK') def __str__(self): d = '' if self.deaduntil: d = " (dead until %d)" % self.deaduntil if self.family == socket.AF_INET: return "inet:%s:%d%s" % (self.address[0], self.address[1], d) elif self.family == socket.AF_INET6: return "inet6:[%s]:%d%s" % (self.address[0], self.address[1], d) else: return "unix:%s%s" % (self.address, d) def _doctest(): import doctest, memcache servers = ["127.0.0.1:11211"] mc = Client(servers, debug=1) globs = {"mc": mc} return doctest.testmod(memcache, globs=globs) if __name__ == "__main__": failures = 0 print "Testing docstrings..." _doctest() print "Running tests:" print serverList = [["127.0.0.1:11211"]] if '--do-unix' in sys.argv: serverList.append([os.path.join(os.getcwd(), 'memcached.socket')]) for servers in serverList: mc = Client(servers, debug=1) def to_s(val): if not isinstance(val, basestring): return "%s (%s)" % (val, type(val)) return "%s" % val def test_setget(key, val): global failures print "Testing set/get {'%s': %s} ..." % (to_s(key), to_s(val)), mc.set(key, val) newval = mc.get(key) if newval == val: print "OK" return 1 else: print "FAIL"; failures = failures + 1 return 0 class FooStruct(object): def __init__(self): self.bar = "baz" def __str__(self): return "A FooStruct" def __eq__(self, other): if isinstance(other, FooStruct): return self.bar == other.bar return 0 test_setget("a_string", "some random string") test_setget("an_integer", 42) if test_setget("long", long(1<<30)): print "Testing delete ...", if mc.delete("long"): print "OK" else: print "FAIL"; failures = failures + 1 print "Checking results of delete ..." if mc.get("long") == None: print "OK" else: print "FAIL"; failures = failures + 1 print "Testing get_multi ...", print mc.get_multi(["a_string", "an_integer"]) # removed from the protocol #if test_setget("timed_delete", 'foo'): # print "Testing timed delete ...", # if mc.delete("timed_delete", 1): # print "OK" # else: # print "FAIL"; failures = failures + 1 # print "Checking results of timed delete ..." # if mc.get("timed_delete") == None: # print "OK" # else: # print "FAIL"; failures = failures + 1 print "Testing get(unknown value) ...", print to_s(mc.get("unknown_value")) f = FooStruct() test_setget("foostruct", f) print "Testing incr ...", x = mc.incr("an_integer", 1) if x == 43: print "OK" else: print "FAIL"; failures = failures + 1 print "Testing decr ...", x = mc.decr("an_integer", 1) if x == 42: print "OK" else: print "FAIL"; failures = failures + 1 sys.stdout.flush() # sanity tests print "Testing sending spaces...", sys.stdout.flush() try: x = mc.set("this has spaces", 1) except Client.MemcachedKeyCharacterError, msg: print "OK" else: print "FAIL"; failures = failures + 1 print "Testing sending control characters...", try: x = mc.set("this\x10has\x11control characters\x02", 1) except Client.MemcachedKeyCharacterError, msg: print "OK" else: print "FAIL"; failures = failures + 1 print "Testing using insanely long key...", try: x = mc.set('a'*SERVER_MAX_KEY_LENGTH, 1) except Client.MemcachedKeyLengthError, msg: print "FAIL"; failures = failures + 1 else: print "OK" try: x = mc.set('a'*SERVER_MAX_KEY_LENGTH + 'a', 1) except Client.MemcachedKeyLengthError, msg: print "OK" else: print "FAIL"; failures = failures + 1 print "Testing sending a unicode-string key...", try: x = mc.set(unicode('keyhere'), 1) except Client.MemcachedStringEncodingError, msg: print "OK", else: print "FAIL",; failures = failures + 1 try: x = mc.set((unicode('a')*SERVER_MAX_KEY_LENGTH).encode('utf-8'), 1) except: print "FAIL",; failures = failures + 1 else: print "OK", import pickle s = pickle.loads('V\\u4f1a\np0\n.') try: x = mc.set((s*SERVER_MAX_KEY_LENGTH).encode('utf-8'), 1) except Client.MemcachedKeyLengthError: print "OK" else: print "FAIL"; failures = failures + 1 print "Testing using a value larger than the memcached value limit..." print 'NOTE: "MemCached: while expecting[...]" is normal...' x = mc.set('keyhere', 'a'*SERVER_MAX_VALUE_LENGTH) if mc.get('keyhere') == None: print "OK", else: print "FAIL",; failures = failures + 1 x = mc.set('keyhere', 'a'*SERVER_MAX_VALUE_LENGTH + 'aaa') if mc.get('keyhere') == None: print "OK" else: print "FAIL"; failures = failures + 1 print "Testing set_multi() with no memcacheds running", mc.disconnect_all() errors = mc.set_multi({'keyhere' : 'a', 'keythere' : 'b'}) if errors != []: print "FAIL"; failures = failures + 1 else: print "OK" print "Testing delete_multi() with no memcacheds running", mc.disconnect_all() ret = mc.delete_multi({'keyhere' : 'a', 'keythere' : 'b'}) if ret != 1: print "FAIL"; failures = failures + 1 else: print "OK" if failures > 0: print '*** THERE WERE FAILED TESTS' sys.exit(1) sys.exit(0) # vim: ts=4 sw=4 et : python-memcached-1.53/memcache.html0000664002342000234200000011521012154412333015733 0ustar jafojafo Python: module memcache
 
 
memcache (version 1.53)
index
/tmp/python-memcached-1.53/memcache.py

client module for memcached (memory cache daemon)
 
Overview
========
 
See U{the MemCached homepage<http://www.danga.com/memcached>} for more about memcached.
 
Usage summary
=============
 
This should give you a feel for how this module operates::
 
    import memcache
    mc = memcache.Client(['127.0.0.1:11211'], debug=0)
 
    mc.set("some_key", "Some value")
    value = mc.get("some_key")
 
    mc.set("another_key", 3)
    mc.delete("another_key")
 
    mc.set("key", "1")   # note that the key used for incr/decr must be a string.
    mc.incr("key")
    mc.decr("key")
 
The standard way to use memcache with a database is like this::
 
    key = derive_key(obj)
    obj = mc.get(key)
    if not obj:
        obj = backend_api.get(...)
        mc.set(key, obj)
 
    # we now have obj, and future passes through this code
    # will use the object from the cache.
 
Detailed Documentation
======================
 
More detailed documentation is available in the L{Client} class.

 
Modules
       
os
cPickle
re
socket
sys
time

 
Classes
       
thread._local(__builtin__.object)
Client

 
class Client(thread._local)
    Object representing a pool of memcache servers.
 
See L{memcache} for an overview.
 
In all cases where a key is used, the key can be either:
    1. A simple hashable type (string, integer, etc.).
    2. A tuple of C{(hashvalue, key)}.  This is useful if you want to avoid
    making this module calculate a hash value.  You may prefer, for
    example, to keep all of a given user's objects on the same memcache
    server, so you could use the user's unique id as the hash value.
 
@group Setup: __init__, set_servers, forget_dead_hosts, disconnect_all, debuglog
@group Insertion: set, add, replace, set_multi
@group Retrieval: get, get_multi
@group Integers: incr, decr
@group Removal: delete, delete_multi
@sort: __init__, set_servers, forget_dead_hosts, disconnect_all, debuglog,           set, set_multi, add, replace, get, get_multi, incr, decr, delete, delete_multi
 
 
Method resolution order:
Client
thread._local
__builtin__.object

Methods defined here:
__init__(self, servers, debug=0, pickleProtocol=0, pickler=<built-in function Pickler>, unpickler=<built-in function Unpickler>, pload=None, pid=None, server_max_key_length=250, server_max_value_length=1048576, dead_retry=30, socket_timeout=3, cache_cas=False, flush_on_reconnect=0, check_keys=True)
Create a new Client object with the given list of servers.
 
@param servers: C{servers} is passed to L{set_servers}.
@param debug: whether to display error messages when a server can't be
contacted.
@param pickleProtocol: number to mandate protocol used by (c)Pickle.
@param pickler: optional override of default Pickler to allow subclassing.
@param unpickler: optional override of default Unpickler to allow subclassing.
@param pload: optional persistent_load function to call on pickle loading.
Useful for cPickle since subclassing isn't allowed.
@param pid: optional persistent_id function to call on pickle storing.
Useful for cPickle since subclassing isn't allowed.
@param dead_retry: number of seconds before retrying a blacklisted
server. Default to 30 s.
@param socket_timeout: timeout in seconds for all calls to a server. Defaults
to 3 seconds.
@param cache_cas: (default False) If true, cas operations will be
cached.  WARNING: This cache is not expired internally, if you have
a long-running process you will need to expire it manually via
client.reset_cas(), or the cache can grow unlimited.
@param server_max_key_length: (default SERVER_MAX_KEY_LENGTH)
Data that is larger than this will not be sent to the server.
@param server_max_value_length: (default SERVER_MAX_VALUE_LENGTH)
Data that is larger than this will not be sent to the server.
@param flush_on_reconnect: optional flag which prevents a scenario that
can cause stale data to be read: If there's more than one memcached
server and the connection to one is interrupted, keys that mapped to
that server will get reassigned to another. If the first server comes
back, those keys will map to it again. If it still has its data, get()s
can read stale data that was overwritten on another server. This flag
is off by default for backwards compatibility.
@param check_keys: (default True) If True, the key is checked to
ensure it is the correct length and composed of the right characters.
add(self, key, val, time=0, min_compress_len=0)
Add new key with value.
 
Like L{set}, but only stores in memcache if the key doesn't already exist.
 
@return: Nonzero on success.
@rtype: int
append(self, key, val, time=0, min_compress_len=0)
Append the value to the end of the existing key's value.
 
Only stores in memcache if key already exists.
Also see L{prepend}.
 
@return: Nonzero on success.
@rtype: int
cas(self, key, val, time=0, min_compress_len=0)
Sets a key to a given value in the memcache if it hasn't been
altered since last fetched. (See L{gets}).
 
The C{key} can optionally be an tuple, with the first element
being the server hash value and the second being the key.
If you want to avoid making this module calculate a hash value.
You may prefer, for example, to keep all of a given user's objects
on the same memcache server, so you could use the user's unique
id as the hash value.
 
@return: Nonzero on success.
@rtype: int
@param time: Tells memcached the time which this value should expire,
either as a delta number of seconds, or an absolute unix
time-since-the-epoch value. See the memcached protocol docs section
"Storage Commands" for more info on <exptime>. We default to
0 == cache forever.
@param min_compress_len: The threshold length to kick in
auto-compression of the value using the zlib.compress() routine. If
the value being cached is a string, then the length of the string is
measured, else if the value is an object, then the length of the
pickle result is measured. If the resulting attempt at compression
yeilds a larger string than the input, then it is discarded. For
backwards compatability, this parameter defaults to 0, indicating
don't ever try to compress.
check_key(self, key, key_extra_len=0)
Checks sanity of key.  Fails if:
Key length is > SERVER_MAX_KEY_LENGTH (Raises MemcachedKeyLength).
Contains control characters  (Raises MemcachedKeyCharacterError).
Is not a string (Raises MemcachedStringEncodingError)
Is an unicode string (Raises MemcachedStringEncodingError)
Is not a string (Raises MemcachedKeyError)
Is None (Raises MemcachedKeyError)
debuglog(self, str)
decr(self, key, delta=1)
Like L{incr}, but decrements.  Unlike L{incr}, underflow is checked and
new values are capped at 0.  If server value is 1, a decrement of 2
returns 0, not -1.
 
@param delta: Integer amount to decrement by (should be zero or greater).
@return: New value after decrementing or None on error.
@rtype: int
delete(self, key, time=0)
Deletes a key from the memcache.
 
@return: Nonzero on success.
@param time: number of seconds any subsequent set / update commands
should fail. Defaults to None for no delay.
@rtype: int
delete_multi(self, keys, time=0, key_prefix='')
Delete multiple keys in the memcache doing just one query.
 
>>> notset_keys = mc.set_multi({'key1' : 'val1', 'key2' : 'val2'})
>>> mc.get_multi(['key1', 'key2']) == {'key1' : 'val1', 'key2' : 'val2'}
1
>>> mc.delete_multi(['key1', 'key2'])
1
>>> mc.get_multi(['key1', 'key2']) == {}
1
 
 
This method is recommended over iterated regular L{delete}s as it reduces total latency, since
your app doesn't have to wait for each round-trip of L{delete} before sending
the next one.
 
@param keys: An iterable of keys to clear
@param time: number of seconds any subsequent set / update commands should fail. Defaults to 0 for no delay.
@param key_prefix:  Optional string to prepend to each key when sending to memcache.
    See docs for L{get_multi} and L{set_multi}.
 
@return: 1 if no failure in communication with any memcacheds.
@rtype: int
disconnect_all(self)
flush_all(self)
Expire all data in memcache servers that are reachable.
forget_dead_hosts(self)
Reset every host in the pool to an "alive" state.
get(self, key)
Retrieves a key from the memcache.
 
@return: The value or None.
get_multi(self, keys, key_prefix='')
Retrieves multiple keys from the memcache doing just one query.
 
>>> success = mc.set("foo", "bar")
>>> success = mc.set("baz", 42)
>>> mc.get_multi(["foo", "baz", "foobar"]) == {"foo": "bar", "baz": 42}
1
>>> mc.set_multi({'k1' : 1, 'k2' : 2}, key_prefix='pfx_') == []
1
 
This looks up keys 'pfx_k1', 'pfx_k2', ... . Returned dict will just have unprefixed keys 'k1', 'k2'.
>>> mc.get_multi(['k1', 'k2', 'nonexist'], key_prefix='pfx_') == {'k1' : 1, 'k2' : 2}
1
 
get_mult [ and L{set_multi} ] can take str()-ables like ints / longs as keys too. Such as your db pri key fields.
They're rotored through str() before being passed off to memcache, with or without the use of a key_prefix.
In this mode, the key_prefix could be a table name, and the key itself a db primary key number.
 
>>> mc.set_multi({42: 'douglass adams', 46 : 'and 2 just ahead of me'}, key_prefix='numkeys_') == []
1
>>> mc.get_multi([46, 42], key_prefix='numkeys_') == {42: 'douglass adams', 46 : 'and 2 just ahead of me'}
1
 
This method is recommended over regular L{get} as it lowers the number of
total packets flying around your network, reducing total latency, since
your app doesn't have to wait for each round-trip of L{get} before sending
the next one.
 
See also L{set_multi}.
 
@param keys: An array of keys.
@param key_prefix: A string to prefix each key when we communicate with memcache.
    Facilitates pseudo-namespaces within memcache. Returned dictionary keys will not have this prefix.
@return:  A dictionary of key/value pairs that were available. If key_prefix was provided, the keys in the retured dictionary will not have it present.
get_slabs(self)
get_stats(self, stat_args=None)
Get statistics from each of the servers.
 
@param stat_args: Additional arguments to pass to the memcache
    "stats" command.
 
@return: A list of tuples ( server_identifier, stats_dictionary ).
    The dictionary contains a number of name/value pairs specifying
    the name of the status field and the string value associated with
    it.  The values are not converted from strings.
gets(self, key)
Retrieves a key from the memcache. Used in conjunction with 'cas'.
 
@return: The value or None.
incr(self, key, delta=1)
Sends a command to the server to atomically increment the value
for C{key} by C{delta}, or by 1 if C{delta} is unspecified.
Returns None if C{key} doesn't exist on server, otherwise it
returns the new value after incrementing.
 
Note that the value for C{key} must already exist in the memcache,
and it must be the string representation of an integer.
 
>>> mc.set("counter", "20")  # returns 1, indicating success
1
>>> mc.incr("counter")
21
>>> mc.incr("counter")
22
 
Overflow on server is not checked.  Be aware of values approaching
2**32.  See L{decr}.
 
@param delta: Integer amount to increment by (should be zero or greater).
@return: New value after incrementing.
@rtype: int
prepend(self, key, val, time=0, min_compress_len=0)
Prepend the value to the beginning of the existing key's value.
 
Only stores in memcache if key already exists.
Also see L{append}.
 
@return: Nonzero on success.
@rtype: int
replace(self, key, val, time=0, min_compress_len=0)
Replace existing key with value.
 
Like L{set}, but only stores in memcache if the key already exists.
The opposite of L{add}.
 
@return: Nonzero on success.
@rtype: int
reset_cas(self)
Reset the cas cache.  This is only used if the Client() object
was created with "cache_cas=True".  If used, this cache does not
expire internally, so it can grow unbounded if you do not clear it
yourself.
set(self, key, val, time=0, min_compress_len=0)
Unconditionally sets a key to a given value in the memcache.
 
The C{key} can optionally be an tuple, with the first element
being the server hash value and the second being the key.
If you want to avoid making this module calculate a hash value.
You may prefer, for example, to keep all of a given user's objects
on the same memcache server, so you could use the user's unique
id as the hash value.
 
@return: Nonzero on success.
@rtype: int
@param time: Tells memcached the time which this value should expire, either
as a delta number of seconds, or an absolute unix time-since-the-epoch
value. See the memcached protocol docs section "Storage Commands"
for more info on <exptime>. We default to 0 == cache forever.
@param min_compress_len: The threshold length to kick in auto-compression
of the value using the zlib.compress() routine. If the value being cached is
a string, then the length of the string is measured, else if the value is an
object, then the length of the pickle result is measured. If the resulting
attempt at compression yeilds a larger string than the input, then it is
discarded. For backwards compatability, this parameter defaults to 0,
indicating don't ever try to compress.
set_multi(self, mapping, time=0, key_prefix='', min_compress_len=0)
Sets multiple keys in the memcache doing just one query.
 
>>> notset_keys = mc.set_multi({'key1' : 'val1', 'key2' : 'val2'})
>>> mc.get_multi(['key1', 'key2']) == {'key1' : 'val1', 'key2' : 'val2'}
1
 
 
This method is recommended over regular L{set} as it lowers the
number of total packets flying around your network, reducing
total latency, since your app doesn't have to wait for each
round-trip of L{set} before sending the next one.
 
@param mapping: A dict of key/value pairs to set.
@param time: Tells memcached the time which this value should
    expire, either as a delta number of seconds, or an absolute
    unix time-since-the-epoch value. See the memcached protocol
    docs section "Storage Commands" for more info on <exptime>. We
    default to 0 == cache forever.
@param key_prefix:  Optional string to prepend to each key when
    sending to memcache. Allows you to efficiently stuff these
    keys into a pseudo-namespace in memcache:
 
    >>> notset_keys = mc.set_multi(
    ...     {'key1' : 'val1', 'key2' : 'val2'}, key_prefix='subspace_')
    >>> len(notset_keys) == 0
    True
    >>> mc.get_multi(['subspace_key1', 'subspace_key2']) == {'subspace_key1' : 'val1', 'subspace_key2' : 'val2'}
    True
 
    Causes key 'subspace_key1' and 'subspace_key2' to be
    set. Useful in conjunction with a higher-level layer which
    applies namespaces to data in memcache.  In this case, the
    return result would be the list of notset original keys,
    prefix not applied.
 
@param min_compress_len: The threshold length to kick in
    auto-compression of the value using the zlib.compress()
    routine. If the value being cached is a string, then
    the length of the string is measured, else if the value
    is an object, then the length of the pickle result is
    measured. If the resulting attempt at compression yeilds
    a larger string than the input, then it is discarded. For
    backwards compatability, this parameter defaults to 0,
    indicating don't ever try to compress.
@return: List of keys which failed to be stored [ memcache out of
   memory, etc. ].
@rtype: list
set_servers(self, servers)
Set the pool of servers used by this client.
 
@param servers: an array of servers.
Servers can be passed in two forms:
    1. Strings of the form C{"host:port"}, which implies a default weight of 1.
    2. Tuples of the form C{("host:port", weight)}, where C{weight} is
    an integer weight value.

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)

Data and other attributes defined here:
MemcachedKeyCharacterError = <class 'memcache.MemcachedKeyCharacterError'>
MemcachedKeyError = <class 'memcache.MemcachedKeyError'>
MemcachedKeyLengthError = <class 'memcache.MemcachedKeyLengthError'>
MemcachedKeyNoneError = <class 'memcache.MemcachedKeyNoneError'>
MemcachedKeyTypeError = <class 'memcache.MemcachedKeyTypeError'>
MemcachedStringEncodingError = <class 'memcache.MemcachedStringEncodingError'>

Methods inherited from thread._local:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value

Data and other attributes inherited from thread._local:
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T

 
Functions
       
StringIO(...)
StringIO([s]) -- Return a StringIO-like stream for reading or writing
cmemcache_hash(key)
compress(...)
compress(string[, level]) -- Returned compressed string.
 
Optional arg level is the compression level, in 1-9.
crc32(...)
(data, oldcrc = 0) -> newcrc. Compute CRC-32 incrementally
decompress(...)
decompress(string[, wbits[, bufsize]]) -- Return decompressed string.
 
Optional arg wbits is the window buffer size.  Optional arg bufsize is
the initial output buffer size.
serverHashFunction = cmemcache_hash(key)
useOldServerHashFunction()
Use the old python-memcache server hash function.

 
Data
        SERVER_MAX_KEY_LENGTH = 250
SERVER_MAX_VALUE_LENGTH = 1048576
__author__ = 'Sean Reifschneider <jafo-memcached@tummy.com>'
__copyright__ = 'Copyright (C) 2003 Danga Interactive'
__license__ = 'Python Software Foundation License'
__version__ = '1.53'
valid_key_chars_re = <_sre.SRE_Pattern object>

 
Author
        Sean Reifschneider <jafo-memcached@tummy.com>
python-memcached-1.53/ChangeLog0000664002342000234200000004135412154412330015061 0ustar jafojafoSun, 07 Jun 2013 11:12:18 -0600 Sean Reifschneider * 1.53 release. * Fixing set_multi() so that if the server closes the connection it will no longer raise AttributeError. Issue found and resolution reviewed by Ben Hoyt. * readline() now will mark the connection dead if the read fails. It was just closing it before. This is related to the set_multi() change but worth noting separately. Thanks to Ben Hoyt. * Discussion of the above: https://github.com/linsomniac/python-memcached/commit/b7054a964aed0e6d86e853e60aab09cd0183b9f6#commitcomment-3337557 Sun, 02 Jun 2013 01:08:26 -0600 Sean Reifschneider * 1.52 release. * Changing check_keys to use re.match() instead of str.translate(), because re.match() works with Python < 2.6. Found by Giovanni Di Milia. Mon, 06 May 2013 15:29:07 -0600 Sean Reifschneider * 1.51 release. * Add a MANIFEST.in file, patch by Daniel Widerin. Mon, 06 May 2013 07:20:21 -0600 Sean Reifschneider * 1.50 release. * Client() now takes a "check_keys" option, which defaults to True. If False, it disables the checking of keys to ensure they have acceptable size and are composed of non-control characters. Suggested by Ben Hoyt. * Converting control character checking of keys based on performance testing of alternatives by Ben Hoyt. * Converted unicode tests from using u'', patch from Eren Güve. * Included license file (pull request by "Philippe" pombredanne). * Doing a "set" after server goes away, raised AttributeError: 'NoneType' object has no attribute 'sendall'. Patch by Ken Lalonde * incr/decr return None instead of 0 on server connection failure. Suggested by Ivan Virabyan * Supports IPv6 connections using: "inet6:[fd00::32:19f7]:11000". Patch by Romain Courteaud * Switching over to github for this project: https://github.com/linsomniac * Bug #974632: _ConnectionDeadError sometimes was escaping the get/set code. This should return to readline() not raising an exception, except in the case that it's called from the get/set(). Report from Gary Poster, proposed patch by Brad Crittenden. Misc fixes by Brad Crittenden: fixing a docstring, if "port" is set to any false-like value it will default to 11211. Mon, 29 Nov 2011 12:37:32 -0700 Sean Reifschneider * Bug #887765: Interrupted connection to memcache server can cause inconsistencies. Added "flush_on_reconnect" (defaults to off) to Client() which will cause a client that has lost connection to a server and then reconnects to flush the cache on the reconnect so that it doesn't get old values from that server. Patch by Daniel Benamy. Sun, 27 Nov 2011 18:15:32 -0700 Sean Reifschneider * Bug #745633: Values of maximum size are not stored API inconsistency, max value length was tested for <= while max KEY length was <. So I picked that keys and values *LONGER* than the specified max value are what is used, and added documentation and tests to that effect. The test for max value tested that length plus 4, so I've changed that to be that value plus 1. Issue found by matt-quru. * Bug #713488: Issues Invalid "delete" command. Protocol has changed so that the "delete" operation no longer takes a "time" argument. It seems that some servers will refuse a "delete key 0" while others will accept it, but the official server will NOT accept "delete key 1". So I've changed it so that if no "time" argument is specified, no time argument is sent to the server. * Bug #713451: server.expect("END") needs to be in a finally block Expect an "END" when the _recv_value() raises an exception. Patch by Jay Farrimond. * Bug: #741090: cas cache can grow unbounded. Default now is that the cache is not used, unless the "Client()" object is created with "cache_cas=True". In that case, you need to have your own cas clearing code, a simple one would be to use Client().reset_cas() to completely clear the cas_ids cache. Problem pointed out by Shaun Cutts. * Bug #728359: Make python-memcache work on memcache restarts. Patch by Tarek Ziade', reviewed and further patches submitted by Hugo Beauze'e-Luysse and Neganov Alexandr. * Bug #798342: If memcached server sends unknown flag in response for "get", results in: "UnboundLocalError: local variable 'val' referenced before assignment" Now returns "None" instead. Patch by Sharoon Thomas Mon, 20 Dec 2010 19:14:17 -0700 Sean Reifschneider * Bug #680359: useOldServerHashFunction() is broken. It now correctly switches back to the old memcache hash function. Thu, 16 Dec 2010 02:07:40 -0700 Sean Reifschneider * Bug #471727: Changed the delete() code to explicitly check for both NOT_FOUND and DELETED as the responses and return successful for both. It also logs an error if one of these two responses is not found. Also added a test to ensure that delete() works. * When using set_multi and one value is too big, traceback TypeError: 'int' object is unsubscriptable Patch by Orjan Persson * Fixing Bug #529855: Server host can now be bare host without ":". Fix proposed by Roger Binns. * Fixing Bug #491164: Typo fix, "compession" -> "compRession". * Fixing Bug #509712: "TypeError: 'NoneType' object is unsubscriptable" Also fixed some other similar code to not have issues with that. * Also related to 509712 and 628339: readline() now returns '' instead of None when a server dies. This should be safer. Patch suggested by Denis Otkidach. * Fixing Bug #628339: Read from server sometimes fails. Patch by Jeremy Cowles. * Fixing Bug #633553: Add stat arguments support to get_stats(). Patch by Ryan Lane. * Changing the license to the PSF License. * Removing Evan's e-mail address at his request, changing authorship to Sean. Sat, 28 Nov 2009 01:07:42 -0700 Sean Reifschneider * Version 1.45 * Per-connection max server key length. Patch by Nicolas Delaby * Patches to make memcached more garbage-collectable. Removes "debugfunc" argument from _Host objects and changed to "debug" boolean. Patches by John McFarlane and Aryeh Katz. * Switching to a cmemcache compatible hash function. Implemented by André Cru and Ludvig Ericson. To switch back to the old style, use: memcached.useOldServerHashFunction() * Rejecting keys that have spaces in them. Patch by Etienne Posthumus. * Fixing exception raising syntax. Patch by Samuel Stauffer. * Optimizations in read code. Patch by Samuel Stauffer. * Changing classes to be newstyle. Patch by Samuel Stauffer. * Changed "has_key" to "in". Patch by Samuel Stauffer. * incr/decr were raising ValueError if the key did not exist, the docstring said it returned none. Patch by Chihiro Sakatoku. * Adding cas method, submitted by Ben Gutierrez. * Fix in the docstring for how to use the "set" method. Found and fixed by William McVey Thu, 02 Apr 2009 13:37:49 -0600 Sean Reifschneider * Version 1.44 * Allowing spaces in the key. (Patch provided by xmm on Launchpad) * Detecting when the pickler needs a positional argument. (Patch provided by Brad Clements on Launchpad) * Moving length check after the compression. (Patch provided by user Tom on Launchpad) * Fixing arguments passed to the _Error if invalid read length. * Fixing the representation of domain sockets. (Patch provided by user MTB on Launchpad) * Changing a typo of dead_until. (Patch provided by Shane R. Spencer) * Providing better error messages (patch provided by Johan Euphrosine). * Adding get_slabs() function to get stats. (Patch provided by Nick Verbeck) Sun, 01 Jun 2008 15:05:11 -0600 Sean Reifschneider * Version 1.43 * eliott reported a bug in the 1.42 related to the socket timeout code causing a traceback due to the timeout value not being set. Sat, 31 May 2008 02:09:17 -0600 Sean Reifschneider * Version 1.42 * Paul Hummer set up a Launchpad project which I'm going to start using to track patches and allow users to set up their own bzr branches and manage marging in the upstream patches with their own. https://launchpad.net/python-memcached * Patch from Jehiah Czebotar which does: Changing the calls to mark_dead() to make them dereference tuples, reducing timeout on sockets to 3 seconds, settable via setting Host._SOCKET_TIMEOUT. * Patches from Steve Schwarz for set_multi() to return the full set of keys if all servers are down. Previously would not report any keys. * Fix from Steve Schwarz delete_multi() argument "seconds" not being correctly handled. Changed it to "time" to match all other calls. * Patch from Peter Wilkinson to support using unix domain sockets. He reports that tests succeed with with memcached daemons running, the normal and a domain socket started via "memcached -s memcached.socket". I massaged it quite a bit. To use domain sockets, use a connect string of "unix:/path/to/socket" Note however that if you are using a host name of "unix", it will now detect "unix:11211" as being a domain socket with the name "11211". In this case, please use "inet:unix:11211". Because of this, it is now preferred to use a connect string prefix of "inet:" or "unix:". Tue, 29 Apr 2008 21:03:53 -0600 Sean Reifschneider * Version 1.41 * Patch from Jehiah Czebotar to catch an additional server disconnect situation. * Patch from Andrey Petrov to add the "append" and "replace" commands. Tue, 18 Sep 2007 20:52:09 -0600 Sean Reifschneider * Version 1.40 * Updated setup.py file that uses distutils provided by Kai Lautaportti. * Prevent keys from containing ASCII character 127 as well, patch provided by Philip Neustrom. * Added ability to overload the persistent_load/id, patch provided by Steve Schwarz. * Fixed ability to pass (server_hash,key) in place of key in Client.set() Reported by Alexander Klyuev. Tue, 14 Aug 2007 14:43:27 -0600 Sean Reifschneider * Version 1.39 * Michael Krause reports the previous version doesn't work for _val_to_store_info() calls because it's defined as a staticmethod. Removing staticmethod decorator. Also confirmed by Kai Lautaportti, with suggested fix of removing staticmethod. Fri, 10 Aug 2007 17:50:13 -0600 Sean Reifschneider * Version 1.38 * Matt McClanahan submitted a patch that allow add() to have a min_compress_len argument. * Steve Schwarz submitted a patch allowing user-defined picklers. * Michael Krause suggested checking the return value to prevent an exception from being raised in _set() when a value is too large to be stored. Fri, 27 Jul 2007 01:55:48 -0600 Sean Reifschneider * Version 1.37 * Fixing call from add() to _set() with parameter for min_compress_len. Reported by Jeff Fisher. Thu, 07 Jun 2007 04:10:31 -0600 Sean Reifschneider * Version 1.36 * Patch by Dave St.Germain to make the Client() class sub-class threadlocal to help with multi-threading issues. Only available in Python 2.4 and above. * Patch by James Robinson with: 1) new set_multi method. 2) factored out determining the flags, length, and value to store from set() into method _val_to_store_info() for use by both set() and set_multi(). 3) send_cmds() method on host which doesn't apply the trailing '\r\n' for use by set_multi. 4) check_key() extended a bit to allow for testing the prefix passed to set_multi just once, not once per each key. 5) Patch also enables support for auto compression in set, set_multi, and replace. * Suggestion by Helge Tesdal, fixes in check_key for non-string keys. * NOTE: On a farm of clients with multiple servers, all clients will need to be upgraded to this version. The next patch changes the server hash. * Philip Neustrom supplied a patch to change the server hash function to binascii.crc32. The original "hash()" call is not cross-platform, so big and little endian systems accessing the same memcache may end up hitting different servers. Restore the old functionality by calling: "memcached.serverHashFunction = hash" after importing memcache. * Philip Neustrom points out that passing Unicode keys or values causes problems because len(key) or len(value) is not equal to the number of bytes that are required to store the key/value. Philip provides a patch which raises an exception in this case. Raises memcache.Client.MemcachedStringEncodingError exception in this case. * NOTE: If you recompiled memcached to increase the default 1MB max value size, you will need to call "memcached.MAX_SERVER_VALUE_LENGTH = N" or memcached will not store values larger than the default 1MB. * Philip Neustrom includes another patch which checks that the key doesn't exceed the memcache server's max size. If it does, the item is silently not stored. * Philip Neustrom added a bunch of sanity checks. * Jehiah Czebotar provided a patch to make the add() and replace() functions return 0 when the add or replace fails, similar to how set() works. Sat, 16 Sep 2006 18:31:46 -0600 Sean Reifschneider * Version 1.34 * In get_multi, if the recv loop reads 0 bytes, raising an EOFError. Identified by Jim Baker. Tue, 05 Sep 2006 14:06:50 -0600 Sean Reifschneider * Version 1.33 * Including patch from Yoshinori K. Okuji to read in larger chunks for readline() calls. This should dramatically improve performance under some circumstances. Sun, 03 Sep 2006 14:02:03 -0600 Sean Reifschneider * Version 1.32 * Including patch from Philip Neustrom which checks keys sent to the server for length and bad characters. Sat, 20 May 2006 14:51:28 -0600 Sean Reifschneider * Version 1.31 * Rolled version 1.30 since the Danga folks are now listing this version as the official version. Removing the "tummy" from the version number, and incrementing so that it's clear it's more recent than "1.2". * Patch applied from Simon Forman for handling of weighted hosts. * Added a little more meat to the README. Sat, 28 Jan 2006 15:59:50 -0700 Sean Reifschneider * cludwin at socallocal suggested that the write-combining with sendall() may not be beneficial. After testing on both SMP and non-SMP machines, I can't see a significant benefit to not doing the write-combining, even on large strings. The benefits of write-combining on smaller strings seems to be significant on UP machines in tight loops. Even on strings that are larger than 2MB, there seems to be no benefit to splitting out the writes. Sun, 18 Sep 2005 18:56:31 -0600 Sean Reifschneider * Changing a printf to debuglog and catching a pickle exception, patch submitted by Justin Azoff. Thu, 14 Jul 2005 11:17:30 -0700 Sean Reifschneider * Alex Stapleton found that the sendall call was slow for writing data larger than several kilobytes. I had him test a change to his patch, which worked as well, but was simpler. The code now does two sendall calls, one for the data and one for the line termination, if the data is larger than 100 bytes. Thu, 7 Apr 2005 14:45:44 -0700 Sean Reifschneider * Incorporating some fixes to get_multi() from Bo Yang Mon, 13 Dec 2004 02:35:17 -0700 Sean Reifschneider * Simplifying the readline() function and speeding it up ~25%. * Fixing a bug in readline() if the server drops, mark_dead() was not being properly called. Sun, 12 Dec 2004 18:56:33 -0700 Sean Reifschneider * Adding "stats()" and "flush_all()" methods. Thu, 10 Aug 2003 12:17:50 -0700 Evan Martin * Slightly more verbose self-test output. * Fix mark_dead() to use proper classname. * Make pooltest.py run from the test directory. Thu, 07 Aug 2003 16:32:32 -0700 Evan Martin * Add incr, decr, and delete. * Better Python (based on comments from Uriah Welcome). * Docs, using epydoc. Thu, 07 Aug 2003 14:20:27 -0700 Evan Martin * Initial prerelease. python-memcached-1.53/.gitignore0000664002342000234200000000000612154412330015264 0ustar jafojafo*.pyc python-memcached-1.53/MANIFEST.in0000664002342000234200000000022612154412330015036 0ustar jafojafoinclude *.md include *.rst include *.txt include ChangeLog include MakeFile global-exclude *.pyc global-exclude .gitignore global-exclude .DS_Store