/client-libraries/python/redis.py
Python | 930 lines | 897 code | 15 blank | 18 comment | 13 complexity | 314fccd652d2b0d68615e677818dbb70 MD5 | raw file
Possible License(s): BSD-3-Clause
1#!/usr/bin/python 2 3""" redis.py - A client for the Redis daemon. 4 5""" 6 7__author__ = "Ludovico Magnocavallo <ludo\x40qix\x2eit>" 8__copyright__ = "Copyright 2009, Ludovico Magnocavallo" 9__license__ = "MIT" 10__version__ = "0.5" 11__revision__ = "$LastChangedRevision: 175 $"[22:-2] 12__date__ = "$LastChangedDate: 2009-03-17 16:15:55 +0100 (Tue, 17 Mar 2009) $"[18:-2] 13 14 15# TODO: Redis._get_multi_response 16 17 18import socket 19 20 21BUFSIZE = 4096 22 23 24class RedisError(Exception): pass 25class ConnectionError(RedisError): pass 26class ResponseError(RedisError): pass 27class InvalidResponse(RedisError): pass 28class InvalidData(RedisError): pass 29 30 31class Redis(object): 32 """The main Redis client. 33 """ 34 35 def __init__(self, host=None, port=None, timeout=None): 36 self.host = host or 'localhost' 37 self.port = port or 6379 38 if timeout: 39 socket.setdefaulttimeout(timeout) 40 self._sock = None 41 self._fp = None 42 43 def _write(self, s): 44 """ 45 >>> r = Redis() 46 >>> r.connect() 47 >>> r._sock.close() 48 >>> try: 49 ... r._write('pippo') 50 ... except ConnectionError, e: 51 ... print e 52 Error 9 while writing to socket. Bad file descriptor. 53 >>> 54 >>> 55 """ 56 try: 57 self._sock.sendall(s) 58 except socket.error, e: 59 if e.args[0] == 32: 60 # broken pipe 61 self.disconnect() 62 raise ConnectionError("Error %s while writing to socket. %s." % tuple(e.args)) 63 64 def _read(self): 65 try: 66 return self._fp.readline() 67 except socket.error, e: 68 if e.args and e.args[0] == errno.EAGAIN: 69 return 70 self.disconnect() 71 raise ConnectionError("Error %s while reading from socket. %s." % tuple(e.args)) 72 if not data: 73 self.disconnect() 74 raise ConnectionError("Socket connection closed when reading.") 75 return data 76 77 def ping(self): 78 """ 79 >>> r = Redis() 80 >>> r.ping() 81 'PONG' 82 >>> 83 """ 84 self.connect() 85 self._write('PING\r\n') 86 return self._get_simple_response() 87 88 def set(self, name, value, preserve=False): 89 """ 90 >>> r = Redis() 91 >>> r.set('a', 'pippo') 92 'OK' 93 >>> try: 94 ... r.set('a', u'pippo \u3235') 95 ... except InvalidData, e: 96 ... print e 97 Error encoding unicode value for key 'a': 'ascii' codec can't encode character u'\u3235' in position 15: ordinal not in range(128). 98 >>> r.set('b', 105.2) 99 'OK' 100 >>> r.set('b', 'xxx', preserve=True) 101 0 102 >>> r.get('b') 103 '105.2' 104 >>> 105 """ 106 self.connect() 107 # the following will raise an error for unicode values that can't be encoded to ascii 108 # we could probably add an 'encoding' arg to init, but then what do we do with get()? 109 # convert back to unicode? and what about ints, or pickled values? 110 try: 111 value = value if isinstance(value, basestring) else str(value) 112 self._write('%s %s %s\r\n%s\r\n' % ( 113 'SETNX' if preserve else 'SET', name, len(value), value 114 )) 115 except UnicodeEncodeError, e: 116 raise InvalidData("Error encoding unicode value for key '%s': %s." % (name, e)) 117 return self._get_numeric_response() if preserve else self._get_simple_response() 118 119 def get(self, name): 120 """ 121 >>> r = Redis() 122 >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n'), r.set('d', '\\r\\n') 123 ('OK', 'OK', 'OK', 'OK') 124 >>> r.get('a') 125 'pippo' 126 >>> r.get('b') 127 '15' 128 >>> r.get('d') 129 '\\r\\n' 130 >>> r.get('b') 131 '15' 132 >>> r.get('c') 133 '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n' 134 >>> r.get('c') 135 '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n' 136 >>> r.get('ajhsd') 137 >>> 138 """ 139 self.connect() 140 self._write('GET %s\r\n' % name) 141 return self._get_value() 142 143 def incr(self, name, amount=1): 144 """ 145 >>> r = Redis() 146 >>> r.delete('a') 147 1 148 >>> r.incr('a') 149 1 150 >>> r.incr('a') 151 2 152 >>> r.incr('a', 2) 153 4 154 >>> 155 """ 156 self.connect() 157 if amount == 1: 158 self._write('INCR %s\r\n' % name) 159 else: 160 self._write('INCRBY %s %s\r\n' % (name, amount)) 161 return self._get_numeric_response() 162 163 def decr(self, name, amount=1): 164 """ 165 >>> r = Redis() 166 >>> if r.get('a'): 167 ... r.delete('a') 168 ... else: 169 ... print 1 170 1 171 >>> r.decr('a') 172 -1 173 >>> r.decr('a') 174 -2 175 >>> r.decr('a', 5) 176 -7 177 >>> 178 """ 179 self.connect() 180 if amount == 1: 181 self._write('DECR %s\r\n' % name) 182 else: 183 self._write('DECRBY %s %s\r\n' % (name, amount)) 184 return self._get_numeric_response() 185 186 def exists(self, name): 187 """ 188 >>> r = Redis() 189 >>> r.exists('dsjhfksjdhfkdsjfh') 190 0 191 >>> r.set('a', 'a') 192 'OK' 193 >>> r.exists('a') 194 1 195 >>> 196 """ 197 self.connect() 198 self._write('EXISTS %s\r\n' % name) 199 return self._get_numeric_response() 200 201 def delete(self, name): 202 """ 203 >>> r = Redis() 204 >>> r.delete('dsjhfksjdhfkdsjfh') 205 0 206 >>> r.set('a', 'a') 207 'OK' 208 >>> r.delete('a') 209 1 210 >>> r.exists('a') 211 0 212 >>> r.delete('a') 213 0 214 >>> 215 """ 216 self.connect() 217 self._write('DEL %s\r\n' % name) 218 return self._get_numeric_response() 219 220 def key_type(self, name): 221 """ 222 Not yet implemented. 223 """ 224 self.connect() 225 self._write('TYPE %s\r\n' % name) 226 return self._get_simple_response() 227 228 def keys(self, pattern): 229 """ 230 >>> r = Redis() 231 >>> r.flush() 232 'OK' 233 >>> r.set('a', 'a') 234 'OK' 235 >>> r.keys('a*') 236 ['a'] 237 >>> r.set('a2', 'a') 238 'OK' 239 >>> r.keys('a*') 240 ['a', 'a2'] 241 >>> r.delete('a2') 242 1 243 >>> r.keys('sjdfhskjh*') 244 [] 245 >>> 246 """ 247 self.connect() 248 self._write('KEYS %s\r\n' % pattern) 249 return self._get_value().split() 250 251 def randomkey(self): 252 """ 253 >>> r = Redis() 254 >>> r.set('a', 'a') 255 'OK' 256 >>> isinstance(r.randomkey(), str) 257 True 258 >>> 259 """ 260 #raise NotImplementedError("Implemented but buggy, do not use.") 261 self.connect() 262 self._write('RANDOMKEY\r\n') 263 data = self._read().strip() 264 self._check_for_error(data) 265 return data 266 267 def rename(self, src, dst, preserve=False): 268 """ 269 >>> r = Redis() 270 >>> try: 271 ... r.rename('a', 'a') 272 ... except ResponseError, e: 273 ... print e 274 src and dest key are the same 275 >>> r.rename('a', 'b') 276 'OK' 277 >>> try: 278 ... r.rename('a', 'b') 279 ... except ResponseError, e: 280 ... print e 281 no such key 282 >>> r.set('a', 1) 283 'OK' 284 >>> r.rename('b', 'a', preserve=True) 285 0 286 >>> 287 """ 288 self.connect() 289 if preserve: 290 self._write('RENAMENX %s %s\r\n' % (src, dst)) 291 return self._get_numeric_response() 292 else: 293 self._write('RENAME %s %s\r\n' % (src, dst)) 294 return self._get_simple_response().strip() 295 296 def push(self, name, value, tail=False): 297 """ 298 >>> r = Redis() 299 >>> r.delete('l') 300 1 301 >>> r.push('l', 'a') 302 'OK' 303 >>> r.set('a', 'a') 304 'OK' 305 >>> try: 306 ... r.push('a', 'a') 307 ... except ResponseError, e: 308 ... print e 309 Operation against a key holding the wrong kind of value 310 >>> 311 """ 312 self.connect() 313 # same considerations on unicode as in set() apply here 314 try: 315 value = value if isinstance(value, basestring) else str(value) 316 self._write('%s %s %s\r\n%s\r\n' % ( 317 'LPUSH' if tail else 'RPUSH', name, len(value), value 318 )) 319 except UnicodeEncodeError, e: 320 raise InvalidData("Error encoding unicode value for element in list '%s': %s." % (name, e)) 321 return self._get_simple_response() 322 323 def llen(self, name): 324 """ 325 >>> r = Redis() 326 >>> r.delete('l') 327 1 328 >>> r.push('l', 'a') 329 'OK' 330 >>> r.llen('l') 331 1 332 >>> r.push('l', 'a') 333 'OK' 334 >>> r.llen('l') 335 2 336 >>> 337 """ 338 self.connect() 339 self._write('LLEN %s\r\n' % name) 340 return self._get_numeric_response() 341 342 def lrange(self, name, start, end): 343 """ 344 >>> r = Redis() 345 >>> r.delete('l') 346 1 347 >>> r.lrange('l', 0, 1) 348 [] 349 >>> r.push('l', 'aaa') 350 'OK' 351 >>> r.lrange('l', 0, 1) 352 ['aaa'] 353 >>> r.push('l', 'bbb') 354 'OK' 355 >>> r.lrange('l', 0, 0) 356 ['aaa'] 357 >>> r.lrange('l', 0, 1) 358 ['aaa', 'bbb'] 359 >>> r.lrange('l', -1, 0) 360 [] 361 >>> r.lrange('l', -1, -1) 362 ['bbb'] 363 >>> 364 """ 365 self.connect() 366 self._write('LRANGE %s %s %s\r\n' % (name, start, end)) 367 return self._get_multi_response() 368 369 def ltrim(self, name, start, end): 370 """ 371 >>> r = Redis() 372 >>> r.delete('l') 373 1 374 >>> try: 375 ... r.ltrim('l', 0, 1) 376 ... except ResponseError, e: 377 ... print e 378 no such key 379 >>> r.push('l', 'aaa') 380 'OK' 381 >>> r.push('l', 'bbb') 382 'OK' 383 >>> r.push('l', 'ccc') 384 'OK' 385 >>> r.ltrim('l', 0, 1) 386 'OK' 387 >>> r.llen('l') 388 2 389 >>> r.ltrim('l', 99, 95) 390 'OK' 391 >>> r.llen('l') 392 0 393 >>> 394 """ 395 self.connect() 396 self._write('LTRIM %s %s %s\r\n' % (name, start, end)) 397 return self._get_simple_response() 398 399 def lindex(self, name, index): 400 """ 401 >>> r = Redis() 402 >>> res = r.delete('l') 403 >>> r.lindex('l', 0) 404 >>> r.push('l', 'aaa') 405 'OK' 406 >>> r.lindex('l', 0) 407 'aaa' 408 >>> r.lindex('l', 2) 409 >>> r.push('l', 'ccc') 410 'OK' 411 >>> r.lindex('l', 1) 412 'ccc' 413 >>> r.lindex('l', -1) 414 'ccc' 415 >>> 416 """ 417 self.connect() 418 self._write('LINDEX %s %s\r\n' % (name, index)) 419 return self._get_value() 420 421 def pop(self, name, tail=False): 422 """ 423 >>> r = Redis() 424 >>> r.delete('l') 425 1 426 >>> r.pop('l') 427 >>> r.push('l', 'aaa') 428 'OK' 429 >>> r.push('l', 'bbb') 430 'OK' 431 >>> r.pop('l') 432 'aaa' 433 >>> r.pop('l') 434 'bbb' 435 >>> r.pop('l') 436 >>> r.push('l', 'aaa') 437 'OK' 438 >>> r.push('l', 'bbb') 439 'OK' 440 >>> r.pop('l', tail=True) 441 'bbb' 442 >>> r.pop('l') 443 'aaa' 444 >>> r.pop('l') 445 >>> 446 """ 447 self.connect() 448 self._write('%s %s\r\n' % ('RPOP' if tail else 'LPOP', name)) 449 return self._get_value() 450 451 def lset(self, name, index, value): 452 """ 453 >>> r = Redis() 454 >>> r.delete('l') 455 1 456 >>> try: 457 ... r.lset('l', 0, 'a') 458 ... except ResponseError, e: 459 ... print e 460 no such key 461 >>> r.push('l', 'aaa') 462 'OK' 463 >>> try: 464 ... r.lset('l', 1, 'a') 465 ... except ResponseError, e: 466 ... print e 467 index out of range 468 >>> r.lset('l', 0, 'bbb') 469 'OK' 470 >>> r.lrange('l', 0, 1) 471 ['bbb'] 472 >>> 473 """ 474 self.connect() 475 try: 476 value = value if isinstance(value, basestring) else str(value) 477 self._write('LSET %s %s %s\r\n%s\r\n' % ( 478 name, index, len(value), value 479 )) 480 except UnicodeEncodeError, e: 481 raise InvalidData("Error encoding unicode value for element %s in list '%s': %s." % (index, name, e)) 482 return self._get_simple_response() 483 484 def lrem(self, name, value, num=0): 485 """ 486 >>> r = Redis() 487 >>> r.delete('l') 488 1 489 >>> r.push('l', 'aaa') 490 'OK' 491 >>> r.push('l', 'bbb') 492 'OK' 493 >>> r.push('l', 'aaa') 494 'OK' 495 >>> r.lrem('l', 'aaa') 496 2 497 >>> r.lrange('l', 0, 10) 498 ['bbb'] 499 >>> r.push('l', 'aaa') 500 'OK' 501 >>> r.push('l', 'aaa') 502 'OK' 503 >>> r.lrem('l', 'aaa', 1) 504 1 505 >>> r.lrem('l', 'aaa', 1) 506 1 507 >>> r.lrem('l', 'aaa', 1) 508 0 509 >>> 510 """ 511 self.connect() 512 try: 513 value = value if isinstance(value, basestring) else str(value) 514 self._write('LREM %s %s %s\r\n%s\r\n' % ( 515 name, num, len(value), value 516 )) 517 except UnicodeEncodeError, e: 518 raise InvalidData("Error encoding unicode value for element %s in list '%s': %s." % (index, name, e)) 519 return self._get_numeric_response() 520 521 def sort(self, name, by=None, get=None, start=None, num=None, desc=False, alpha=False): 522 """ 523 >>> r = Redis() 524 >>> r.delete('l') 525 1 526 >>> r.push('l', 'ccc') 527 'OK' 528 >>> r.push('l', 'aaa') 529 'OK' 530 >>> r.push('l', 'ddd') 531 'OK' 532 >>> r.push('l', 'bbb') 533 'OK' 534 >>> r.sort('l', alpha=True) 535 ['aaa', 'bbb', 'ccc', 'ddd'] 536 >>> r.delete('l') 537 1 538 >>> for i in range(1, 5): 539 ... res = r.push('l', 1.0 / i) 540 >>> r.sort('l') 541 ['0.25', '0.333333333333', '0.5', '1.0'] 542 >>> r.sort('l', desc=True) 543 ['1.0', '0.5', '0.333333333333', '0.25'] 544 >>> r.sort('l', desc=True, start=2, num=1) 545 ['0.333333333333'] 546 >>> r.set('weight_0.5', 10) 547 'OK' 548 >>> r.sort('l', desc=True, by='weight_*') 549 ['0.5', '1.0', '0.333333333333', '0.25'] 550 >>> for i in r.sort('l', desc=True): 551 ... res = r.set('test_%s' % i, 100 - float(i)) 552 >>> r.sort('l', desc=True, get='test_*') 553 ['99.0', '99.5', '99.6666666667', '99.75'] 554 >>> r.sort('l', desc=True, by='weight_*', get='test_*') 555 ['99.5', '99.0', '99.6666666667', '99.75'] 556 >>> r.sort('l', desc=True, by='weight_*', get='missing_*') 557 [None, None, None, None] 558 >>> 559 """ 560 stmt = ['SORT', name] 561 if by: 562 stmt.append("BY %s" % by) 563 if start and num: 564 stmt.append("LIMIT %s %s" % (start, num)) 565 if get is None: 566 pass 567 elif isinstance(get, basestring): 568 stmt.append("GET %s" % get) 569 elif isinstance(get, list) or isinstance(get, tuple): 570 for g in get: 571 stmt.append("GET %s" % g) 572 else: 573 raise RedisError("Invalid parameter 'get' for Redis sort") 574 if desc: 575 stmt.append("DESC") 576 if alpha: 577 stmt.append("ALPHA") 578 self.connect() 579 self._write(' '.join(stmt + ["\r\n"])) 580 return self._get_multi_response() 581 582 def sadd(self, name, value): 583 """ 584 >>> r = Redis() 585 >>> res = r.delete('s') 586 >>> r.sadd('s', 'a') 587 1 588 >>> r.sadd('s', 'b') 589 1 590 >>> 591 """ 592 self.connect() 593 # same considerations on unicode as in set() apply here 594 try: 595 value = value if isinstance(value, basestring) else str(value) 596 self._write('SADD %s %s\r\n%s\r\n' % ( 597 name, len(value), value 598 )) 599 except UnicodeEncodeError, e: 600 raise InvalidData("Error encoding unicode value for element in set '%s': %s." % (name, e)) 601 return self._get_numeric_response() 602 603 def srem(self, name, value): 604 """ 605 >>> r = Redis() 606 >>> r.delete('s') 607 1 608 >>> r.srem('s', 'aaa') 609 0 610 >>> r.sadd('s', 'b') 611 1 612 >>> r.srem('s', 'b') 613 1 614 >>> r.sismember('s', 'b') 615 0 616 >>> 617 """ 618 self.connect() 619 # same considerations on unicode as in set() apply here 620 try: 621 value = value if isinstance(value, basestring) else str(value) 622 self._write('SREM %s %s\r\n%s\r\n' % ( 623 name, len(value), value 624 )) 625 except UnicodeEncodeError, e: 626 raise InvalidData("Error encoding unicode value for element in set '%s': %s." % (name, e)) 627 return self._get_numeric_response() 628 629 def sismember(self, name, value): 630 """ 631 >>> r = Redis() 632 >>> r.delete('s') 633 1 634 >>> r.sismember('s', 'b') 635 0 636 >>> r.sadd('s', 'a') 637 1 638 >>> r.sismember('s', 'b') 639 0 640 >>> r.sismember('s', 'a') 641 1 642 >>> 643 """ 644 self.connect() 645 # same considerations on unicode as in set() apply here 646 try: 647 value = value if isinstance(value, basestring) else str(value) 648 self._write('SISMEMBER %s %s\r\n%s\r\n' % ( 649 name, len(value), value 650 )) 651 except UnicodeEncodeError, e: 652 raise InvalidData("Error encoding unicode value for element in set '%s': %s." % (name, e)) 653 return self._get_numeric_response() 654 655 def sinter(self, *args): 656 """ 657 >>> r = Redis() 658 >>> res = r.delete('s1') 659 >>> res = r.delete('s2') 660 >>> res = r.delete('s3') 661 >>> r.sadd('s1', 'a') 662 1 663 >>> r.sadd('s2', 'a') 664 1 665 >>> r.sadd('s3', 'b') 666 1 667 >>> try: 668 ... r.sinter() 669 ... except ResponseError, e: 670 ... print e 671 wrong number of arguments 672 >>> try: 673 ... r.sinter('l') 674 ... except ResponseError, e: 675 ... print e 676 Operation against a key holding the wrong kind of value 677 >>> r.sinter('s1', 's2', 's3') 678 set([]) 679 >>> r.sinter('s1', 's2') 680 set(['a']) 681 >>> 682 """ 683 self.connect() 684 self._write('SINTER %s\r\n' % ' '.join(args)) 685 return set(self._get_multi_response()) 686 687 def sinterstore(self, dest, *args): 688 """ 689 >>> r = Redis() 690 >>> res = r.delete('s1') 691 >>> res = r.delete('s2') 692 >>> res = r.delete('s3') 693 >>> r.sadd('s1', 'a') 694 1 695 >>> r.sadd('s2', 'a') 696 1 697 >>> r.sadd('s3', 'b') 698 1 699 >>> r.sinterstore('s_s', 's1', 's2', 's3') 700 'OK' 701 >>> r.sinterstore('s_s', 's1', 's2') 702 'OK' 703 >>> r.smembers('s_s') 704 set(['a']) 705 >>> 706 """ 707 self.connect() 708 self._write('SINTERSTORE %s %s\r\n' % (dest, ' '.join(args))) 709 return self._get_simple_response() 710 711 def smembers(self, name): 712 """ 713 >>> r = Redis() 714 >>> r.delete('s') 715 1 716 >>> r.sadd('s', 'a') 717 1 718 >>> r.sadd('s', 'b') 719 1 720 >>> try: 721 ... r.smembers('l') 722 ... except ResponseError, e: 723 ... print e 724 Operation against a key holding the wrong kind of value 725 >>> r.smembers('s') 726 set(['a', 'b']) 727 >>> 728 """ 729 self.connect() 730 self._write('SMEMBERS %s\r\n' % name) 731 return set(self._get_multi_response()) 732 733 def select(self, db): 734 """ 735 >>> r = Redis() 736 >>> r.delete('a') 737 1 738 >>> r.select(1) 739 'OK' 740 >>> r.set('a', 1) 741 'OK' 742 >>> r.select(0) 743 'OK' 744 >>> r.get('a') 745 >>> 746 """ 747 self.connect() 748 self._write('SELECT %s\r\n' % db) 749 return self._get_simple_response() 750 751 def move(self, name, db): 752 """ 753 >>> r = Redis() 754 >>> r.select(0) 755 'OK' 756 >>> r.set('a', 'a') 757 'OK' 758 >>> r.select(1) 759 'OK' 760 >>> if r.get('a'): 761 ... r.delete('a') 762 ... else: 763 ... print 1 764 1 765 >>> r.select(0) 766 'OK' 767 >>> r.move('a', 1) 768 1 769 >>> r.get('a') 770 >>> r.select(1) 771 'OK' 772 >>> r.get('a') 773 'a' 774 >>> r.select(0) 775 'OK' 776 >>> 777 """ 778 self.connect() 779 self._write('MOVE %s %s\r\n' % (name, db)) 780 return self._get_numeric_response() 781 782 def save(self, background=False): 783 """ 784 >>> r = Redis() 785 >>> r.save() 786 'OK' 787 >>> try: 788 ... resp = r.save(background=True) 789 ... except ResponseError, e: 790 ... assert str(e) == 'background save already in progress', str(e) 791 ... else: 792 ... assert resp == 'OK' 793 >>> 794 """ 795 self.connect() 796 if background: 797 self._write('BGSAVE\r\n') 798 else: 799 self._write('SAVE\r\n') 800 return self._get_simple_response() 801 802 def lastsave(self): 803 """ 804 >>> import time 805 >>> r = Redis() 806 >>> t = int(time.time()) 807 >>> r.save() 808 'OK' 809 >>> r.lastsave() >= t 810 True 811 >>> 812 """ 813 self.connect() 814 self._write('LASTSAVE\r\n') 815 return self._get_numeric_response() 816 817 def flush(self, all_dbs=False): 818 """ 819 >>> r = Redis() 820 >>> r.flush() 821 'OK' 822 >>> r.flush(all_dbs=True) 823 'OK' 824 >>> 825 """ 826 self.connect() 827 self._write('%s\r\n' % ('FLUSHALL' if all_dbs else 'FLUSHDB')) 828 return self._get_simple_response() 829 830 def _get_value(self, negative_as_nil=False): 831 data = self._read().strip() 832 if data == 'nil' or (negative_as_nil and data == '-1'): 833 return 834 elif data[0] == '-': 835 self._check_for_error(data) 836 try: 837 l = int(data) 838 except (TypeError, ValueError): 839 raise ResponseError("Cannot parse response '%s' as data length." % data) 840 buf = [] 841 while l > 0: 842 data = self._read() 843 l -= len(data) 844 if len(data) > l: 845 # we got the ending crlf 846 data = data.rstrip() 847 buf.append(data) 848 if l == 0: 849 # the data has a trailing crlf embedded, let's restore it 850 buf.append(self._read()) 851 return ''.join(buf) 852 853 def _get_simple_response(self): 854 data = self._read().strip() 855 if data[0] == '+': 856 return data[1:] 857 self._check_for_error(data) 858 raise InvalidResponse("Cannot parse first line '%s' for a simple response." % data, data) 859 860 def _get_numeric_response(self, allow_negative=True): 861 data = self._read().strip() 862 try: 863 value = int(data) 864 except (TypeError, ValueError), e: 865 pass 866 else: 867 if not allow_negative and value < 0: 868 self._check_for_error(data) 869 return value 870 self._check_for_error(data) 871 raise InvalidResponse("Cannot parse first line '%s' for a numeric response: %s." % (data, e), data) 872 873 def _get_multi_response(self): 874 results = list() 875 try: 876 num = self._get_numeric_response(allow_negative=False) 877 except InvalidResponse, e: 878 if e.args[1] == 'nil': 879 return results 880 raise 881 while num: 882 results.append(self._get_value(negative_as_nil=True)) 883 num -= 1 884 return results 885 886 def _check_for_error(self, data): 887 if not data or data[0] != '-': 888 return 889 if data.startswith('-ERR'): 890 raise ResponseError(data[4:].strip()) 891 try: 892 error_len = int(data[1:]) 893 except (TypeError, ValueError): 894 raise ResponseError("Unknown error format '%s'." % data) 895 error_message = self._read().strip()[5:] 896 raise ResponseError(error_message) 897 898 def disconnect(self): 899 if isinstance(self._sock, socket.socket): 900 try: 901 self._sock.close() 902 except socket.error: 903 pass 904 self._sock = None 905 self._fp = None 906 907 def connect(self): 908 """ 909 >>> r = Redis() 910 >>> r.connect() 911 >>> isinstance(r._sock, socket.socket) 912 True 913 >>> 914 """ 915 if isinstance(self._sock, socket.socket): 916 return 917 try: 918 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 919 sock.connect((self.host, self.port)) 920 except socket.error, e: 921 raise ConnectionError("Error %s connecting to %s:%s. %s." % (e.args[0], self.host, self.port, e.args[1])) 922 else: 923 self._sock = sock 924 self._fp = self._sock.makefile('r') 925 926 927if __name__ == '__main__': 928 import doctest 929 doctest.testmod() 930