def _fetch_cmd(self, name, keys, expect_cas): if name == b'stats': # stats commands can have multiple arguments # `stats cachedump 1 1` checked_keys = [self.check_key(k) for k in keys] cmd = name + b' ' + b' '.join(checked_keys) + b'\r\n' else: checked_keys = dict((self.check_key(k), k) for k in keys) cmd = name + b' ' + b' '.join(checked_keys) + b'\r\n' try: if not self.sock: self._connect() self.sock.sendall(cmd) buf = b'' result = {} while True: buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line == b'END': return result elif line.startswith(b'VALUE'): if expect_cas: _, key, flags, size, cas = line.split() else: try: _, key, flags, size = line.split() except Exception as e: raise ValueError("Unable to parse line %s: %s" % (line, str(e))) buf, value = _readvalue(self.sock, buf, int(size)) key = checked_keys[key] if self.deserializer: value = self.deserializer(key, value, int(flags)) if expect_cas: result[key] = (value, cas) else: result[key] = value elif name == b'stats' and line.startswith(b'STAT'): key_value = line.split() result[key_value[1]] = key_value[2] elif name == b'stats' and line.startswith(b'ITEM'): # For 'stats cachedump' commands key_value = line.split() result[key_value[1]] = b' '.join(key_value[2:]) else: raise MemcacheUnknownError(line[:32]) except Exception: self.close() if self.ignore_exc: return {} raise
def test_retry_for_exception_fail(self): # Test that we do not retry for unapproved exception. client = self.make_client( [MemcacheUnknownError("Whoops."), b"VALUE key 0 5\r\nvalue\r\nEND\r\n"], attempts=2, retry_for=tuple([MemcacheClientError]), ) with pytest.raises(MemcacheUnknownError): client.get("key")
def _fetch_cmd(self, name, keys, expect_cas): prefixed_keys = [self.check_key(k) for k in keys] remapped_keys = dict(zip(prefixed_keys, keys)) # It is important for all keys to be listed in their original order. cmd = name + b' ' + b' '.join(prefixed_keys) + b'\r\n' try: if self.sock is None: self._connect() self.sock.sendall(cmd) buf = b'' result = {} while True: buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line == b'END' or line == b'OK': return result elif line.startswith(b'VALUE'): if expect_cas: _, key, flags, size, cas = line.split() else: try: _, key, flags, size = line.split() except Exception as e: raise ValueError("Unable to parse line %s: %s" % (line, str(e))) buf, value = _readvalue(self.sock, buf, int(size)) key = remapped_keys[key] if self.deserializer: value = self.deserializer(key, value, int(flags)) if expect_cas: result[key] = (value, cas) else: result[key] = value elif name == b'stats' and line.startswith(b'STAT'): key_value = line.split() result[key_value[1]] = key_value[2] elif name == b'stats' and line.startswith(b'ITEM'): # For 'stats cachedump' commands key_value = line.split() result[key_value[1]] = b' '.join(key_value[2:]) else: raise MemcacheUnknownError(line[:32]) except Exception: self.close() if self.ignore_exc: return {} raise
def _store_cmd(self, name, key, expire, noreply, data, cas=None): key = self.check_key(key) if not self.sock: self._connect() if self.serializer: data, flags = self.serializer(key, data) else: flags = 0 if not isinstance(data, six.binary_type): try: data = six.text_type(data).encode('ascii') except UnicodeEncodeError as e: raise MemcacheIllegalInputError(str(e)) extra = b'' if cas is not None: extra += b' ' + cas if noreply: extra += b' noreply' cmd = (name + b' ' + key + b' ' + six.text_type(flags).encode('ascii') + b' ' + six.text_type(expire).encode('ascii') + b' ' + six.text_type(len(data)).encode('ascii') + extra + b'\r\n' + data + b'\r\n') try: self.sock.sendall(cmd) if noreply: return True buf = b'' buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line in VALID_STORE_RESULTS[name]: if line == b'STORED': return True if line == b'NOT_STORED': return False if line == b'NOT_FOUND': return None if line == b'EXISTS': return False else: raise MemcacheUnknownError(line[:32]) except Exception: self.close() raise
def _fetch_cluster_info_cmd(self, cmd, name): if self.sock is None: self._connect() self.sock.sendall(cmd) buf = b'' result = {} number_of_line = 0 while True: buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line == b'END': if number_of_line != 2: raise MemcacheUnknownError('Wrong response') return result if number_of_line == 1: try: result = self._extract_cluster_info(line) except ValueError: raise MemcacheUnknownError('Wrong format: {line}'.format( line=line, )) number_of_line += 1
def version(self): """ The memcached "version" command. Returns: A string of the memcached version. """ cmd = b"version\r\n" results = self._misc_cmd([cmd], b'version', False) before, _, after = results[0].partition(b' ') if before != b'VERSION': raise MemcacheUnknownError( "Received unexpected response: %s" % results[0]) return after
def version(self): """ The memcached "version" command. Returns: A string of the memcached version. """ cmd = b"version\r\n" result = self._misc_cmd(cmd, b'version', False) if not result.startswith(b'VERSION '): raise MemcacheUnknownError("Received unexpected response: %s" % (result, )) return result[8:]
def test_both_exception_filters(self): # Test interacction between both exception filters. client = self.make_client([ MemcacheClientError("Whoops."), b'VALUE key 0 5\r\nvalue\r\nEND\r\n', MemcacheUnknownError("Whoops."), b'VALUE key 0 5\r\nvalue\r\nEND\r\n', ], attempts=2, retry_for=tuple([MemcacheClientError]), do_not_retry_for=tuple( [MemcacheUnknownError])) # Check that we succeed where allowed. result = client.get("key") assert result == b'value' # Check that no retries are attempted for the banned exception. with pytest.raises(MemcacheUnknownError): client.get("key")
def _fetch_cmd(self, name, keys, expect_cas): prefixed_keys = [self.check_key(k) for k in keys] remapped_keys = dict(zip(prefixed_keys, keys)) # It is important for all keys to be listed in their original order. cmd = name + b' ' + b' '.join(prefixed_keys) + b'\r\n' try: if self.sock is None: self._connect() self.sock.sendall(cmd) buf = b'' result = {} while True: buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line == b'END' or line == b'OK': return result elif line.startswith(b'VALUE'): key, value, buf = self._extract_value(expect_cas, line, buf, remapped_keys, prefixed_keys) result[key] = value elif name == b'stats' and line.startswith(b'STAT'): key_value = line.split() result[key_value[1]] = key_value[2] elif name == b'stats' and line.startswith(b'ITEM'): # For 'stats cachedump' commands key_value = line.split() result[key_value[1]] = b' '.join(key_value[2:]) else: raise MemcacheUnknownError(line[:32]) except Exception: self.close() if self.ignore_exc: return {} raise
def _store_cmd(self, name, values, expire, noreply, flags=None, cas=None): cmds = [] keys = [] extra = b'' if cas is not None: extra += b' ' + cas if noreply: extra += b' noreply' expire = six.text_type(expire).encode(self.encoding) for key, data in six.iteritems(values): # must be able to reliably map responses back to the original order keys.append(key) key = self.check_key(key) if self.serializer: data, serializer_flags = self.serializer(key, data) # Use the serializer's flags when 'flags' haven't been specified # If 'flags' is specified, ignore the serializer_flags generated # from serializer, otherwise use serializer_flags. if flags is None: flags = serializer_flags # If no 'flags' or 'serializer' passed in, default flags to 0 if flags is None: flags = 0 if not isinstance(data, six.binary_type): try: data = six.text_type(data).encode(self.encoding) except UnicodeEncodeError as e: raise MemcacheIllegalInputError( "Data values must be binary-safe: %s" % e) cmds.append(name + b' ' + key + b' ' + six.text_type(flags).encode(self.encoding) + b' ' + expire + b' ' + six.text_type(len(data)).encode(self.encoding) + extra + b'\r\n' + data + b'\r\n') if self.sock is None: self._connect() try: self.sock.sendall(b''.join(cmds)) if noreply: return {k: True for k in keys} results = {} buf = b'' for key in keys: buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line in VALID_STORE_RESULTS[name]: if line == b'STORED': results[key] = True if line == b'NOT_STORED': results[key] = False if line == b'NOT_FOUND': results[key] = None if line == b'EXISTS': results[key] = False else: raise MemcacheUnknownError(line[:32]) return results except Exception: self.close() raise
def _store_cmd(self, name, values, expire, noreply, flags=None, cas=None): cmds = [] keys = [] extra = b'' if cas is not None: cas = self._check_cas(cas) extra += b' ' + cas if noreply: extra += b' noreply' expire = self._check_integer(expire, "expire") for key, data in six.iteritems(values): # must be able to reliably map responses back to the original order keys.append(key) key = self.check_key(key) data, data_flags = self.serde.serialize(key, data) # If 'flags' was explicitly provided, it overrides the value # returned by the serializer. if flags is not None: data_flags = flags if not isinstance(data, six.binary_type): try: data = six.text_type(data).encode(self.encoding) except UnicodeEncodeError as e: raise MemcacheIllegalInputError( "Data values must be binary-safe: %s" % e) cmds.append(name + b' ' + key + b' ' + six.text_type(data_flags).encode(self.encoding) + b' ' + expire + b' ' + six.text_type(len(data)).encode(self.encoding) + extra + b'\r\n' + data + b'\r\n') if self.sock is None: self._connect() try: self.sock.sendall(b''.join(cmds)) if noreply: return {k: True for k in keys} results = {} buf = b'' for key in keys: buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line in VALID_STORE_RESULTS[name]: if line == b'STORED': results[key] = True if line == b'NOT_STORED': results[key] = False if line == b'NOT_FOUND': results[key] = None if line == b'EXISTS': results[key] = False else: raise MemcacheUnknownError(line[:32]) return results except Exception: self.close() raise
def _store_cmd(self, name, values, expire, noreply, cas=None): cmds = [] keys = [] extra = b'' if cas is not None: extra += b' ' + cas if noreply: extra += b' noreply' expire = six.text_type(expire).encode('ascii') for key, data in six.iteritems(values): # must be able to reliably map responses back to the original order keys.append(key) key = self.check_key(key) if self.serializer: data, flags = self.serializer(key, data) else: flags = 0 if not isinstance(data, six.binary_type): try: data = six.text_type(data).encode('ascii') except UnicodeEncodeError as e: raise MemcacheIllegalInputError(str(e)) cmds.append(name + b' ' + key + b' ' + six.text_type(flags).encode('ascii') + b' ' + expire + b' ' + six.text_type(len(data)).encode('ascii') + extra + b'\r\n' + data + b'\r\n') if not self.sock: self._connect() try: self.sock.sendall(b''.join(cmds)) if noreply: return {k: True for k in keys} results = {} buf = b'' for key in keys: buf, line = _readline(self.sock, buf) self._raise_errors(line, name) if line in VALID_STORE_RESULTS[name]: if line == b'STORED': results[key] = True if line == b'NOT_STORED': results[key] = False if line == b'NOT_FOUND': results[key] = None if line == b'EXISTS': results[key] = False else: raise MemcacheUnknownError(line[:32]) return results except Exception: self.close() raise