From 5173653b2cc11376ba5cd99f72ba6a1cea31087d Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 29 Nov 2021 13:57:51 +0200 Subject: [PATCH 1/5] Run pyupgrade --py36-plus --- benchmarks/base.py | 2 +- benchmarks/basic_operations.py | 6 +-- benchmarks/command_packer_benchmark.py | 5 +- redis/client.py | 4 +- redis/cluster.py | 61 ++++++++++++------------ redis/commands/cluster.py | 12 ++--- redis/commands/core.py | 10 ++-- redis/commands/helpers.py | 2 +- redis/commands/json/path.py | 2 +- redis/commands/parser.py | 2 +- redis/commands/search/__init__.py | 2 +- redis/commands/search/aggregation.py | 18 +++---- redis/commands/search/document.py | 2 +- redis/commands/search/field.py | 2 +- redis/commands/search/indexDefinition.py | 2 +- redis/commands/search/query.py | 10 ++-- redis/commands/search/querystring.py | 12 ++--- redis/commands/search/reducers.py | 24 +++++----- redis/commands/search/result.py | 2 +- redis/commands/search/suggestion.py | 4 +- redis/commands/timeseries/info.py | 2 +- redis/connection.py | 12 ++--- redis/sentinel.py | 16 +++---- tasks.py | 2 +- tests/conftest.py | 12 ++--- tests/test_cluster.py | 19 ++++---- tests/test_commands.py | 26 +++++----- tests/test_search.py | 4 +- tests/test_timeseries.py | 2 +- 29 files changed, 136 insertions(+), 143 deletions(-) diff --git a/benchmarks/base.py b/benchmarks/base.py index 8c13afe34d..029f504a5e 100644 --- a/benchmarks/base.py +++ b/benchmarks/base.py @@ -34,7 +34,7 @@ def run_benchmark(self): group_values = [group['values'] for group in self.ARGUMENTS] for value_set in itertools.product(*group_values): pairs = list(zip(group_names, value_set)) - arg_string = ', '.join(['%s=%s' % (p[0], p[1]) for p in pairs]) + arg_string = ', '.join(f'{p[0]}={p[1]}' for p in pairs) sys.stdout.write('Benchmark: %s... ' % arg_string) sys.stdout.flush() kwargs = dict(pairs) diff --git a/benchmarks/basic_operations.py b/benchmarks/basic_operations.py index 9446343251..079f975dda 100644 --- a/benchmarks/basic_operations.py +++ b/benchmarks/basic_operations.py @@ -49,9 +49,9 @@ def wrapper(*args, **kwargs): count = kwargs['num'] else: count = args[1] - print('{} - {} Requests'.format(func.__name__, count)) - print('Duration = {}'.format(duration)) - print('Rate = {}'.format(count/duration)) + print(f'{func.__name__} - {count} Requests') + print(f'Duration = {duration}') + print(f'Rate = {count/duration}') print() return ret return wrapper diff --git a/benchmarks/command_packer_benchmark.py b/benchmarks/command_packer_benchmark.py index 823a8c8469..978066ddd6 100644 --- a/benchmarks/command_packer_benchmark.py +++ b/benchmarks/command_packer_benchmark.py @@ -1,4 +1,3 @@ -import socket from redis.connection import (Connection, SYM_STAR, SYM_DOLLAR, SYM_EMPTY, SYM_CRLF) from base import Benchmark @@ -11,7 +10,7 @@ def send_packed_command(self, command, check_health=True): self.connect() try: self._sock.sendall(command) - except socket.error as e: + except OSError as e: self.disconnect() if len(e.args) == 1: _errno, errmsg = 'UNKNOWN', e.args[0] @@ -43,7 +42,7 @@ def send_packed_command(self, command, check_health=True): command = [command] for item in command: self._sock.sendall(item) - except socket.error as e: + except OSError as e: self.disconnect() if len(e.args) == 1: _errno, errmsg = 'UNKNOWN', e.args[0] diff --git a/redis/client.py b/redis/client.py index 0ae64be9c9..107072d3ab 100755 --- a/redis/client.py +++ b/redis/client.py @@ -629,7 +629,7 @@ def parse_set_result(response, **options): return response and str_if_bytes(response) == 'OK' -class Redis(RedisModuleCommands, CoreCommands, SentinelCommands, object): +class Redis(RedisModuleCommands, CoreCommands, SentinelCommands): """ Implementation of the Redis protocol. @@ -918,7 +918,7 @@ def __init__(self, host='localhost', port=6379, self.__class__.RESPONSE_CALLBACKS) def __repr__(self): - return "%s<%s>" % (type(self).__name__, repr(self.connection_pool)) + return f"{type(self).__name__}<{repr(self.connection_pool)}>" def set_response_callback(self, command, callback): "Set a custom Response Callback" diff --git a/redis/cluster.py b/redis/cluster.py index 91a4d558a2..9f37a65c37 100644 --- a/redis/cluster.py +++ b/redis/cluster.py @@ -42,7 +42,7 @@ def get_node_name(host, port): - return '{0}:{1}'.format(host, port) + return f'{host}:{port}' def get_connection(redis_node, *args, **options): @@ -200,7 +200,7 @@ class ClusterParser(DefaultParser): }) -class RedisCluster(ClusterCommands, object): +class RedisCluster(ClusterCommands): RedisClusterRequestTTL = 16 PRIMARIES = "primaries" @@ -451,7 +451,7 @@ def __init__( "2. list of startup nodes, for example:\n" " RedisCluster(startup_nodes=[ClusterNode('localhost', 6379)," " ClusterNode('localhost', 6378)])") - log.debug("startup_nodes : {0}".format(startup_nodes)) + log.debug(f"startup_nodes : {startup_nodes}") # Update the connection arguments # Whenever a new connection is established, RedisCluster's on_connect # method should be run @@ -602,7 +602,7 @@ def get_node_from_key(self, key, replica=False): slot_cache = self.nodes_manager.slots_cache.get(slot) if slot_cache is None or len(slot_cache) == 0: raise SlotNotCoveredError( - 'Slot "{0}" is not covered by the cluster.'.format(slot) + f'Slot "{slot}" is not covered by the cluster.' ) if replica and len(self.nodes_manager.slots_cache[slot]) < 2: return None @@ -631,7 +631,7 @@ def set_default_node(self, node): "the default node was not changed.") return False self.nodes_manager.default_node = node - log.info("Changed the default cluster node to {0}".format(node)) + log.info(f"Changed the default cluster node to {node}") return True def pubsub(self, node=None, host=None, port=None, **kwargs): @@ -700,7 +700,7 @@ def _determine_nodes(self, *args, **kwargs): slot = self.determine_slot(*args) node = self.nodes_manager.get_node_from_slot( slot, self.read_from_replicas and command in READ_COMMANDS) - log.debug("Target for {0}: slot {1}".format(args, slot)) + log.debug(f"Target for {args}: slot {slot}") return [node] def _should_reinitialized(self): @@ -741,7 +741,7 @@ def determine_slot(self, *args): raise RedisClusterException( "No way to dispatch this command to Redis Cluster. " "Missing key.\nYou can execute the command by specifying " - "target nodes.\nCommand: {0}".format(args) + "target nodes.\nCommand: {}".format(args) ) if len(keys) > 1: @@ -749,7 +749,7 @@ def determine_slot(self, *args): # the same slot slots = {self.keyslot(key) for key in keys} if len(slots) != 1: - raise RedisClusterException("{0} - all keys must map to the " + raise RedisClusterException("{} - all keys must map to the " "same key slot".format(args[0])) return slots.pop() else: @@ -952,7 +952,7 @@ def _execute_command(self, target_node, *args, **kwargs): raise e except ResponseError as e: message = e.__str__() - log.exception("ResponseError: {0}".format(message)) + log.exception(f"ResponseError: {message}") raise e except BaseException as e: log.exception("BaseException") @@ -995,7 +995,7 @@ def _process_result(self, command, res, **kwargs): return res -class ClusterNode(object): +class ClusterNode: def __init__(self, host, port, server_type=None, redis_connection=None): if host == 'localhost': host = socket.gethostbyname(host) @@ -1007,8 +1007,8 @@ def __init__(self, host, port, server_type=None, redis_connection=None): self.redis_connection = redis_connection def __repr__(self): - return '[host={0},port={1},' \ - 'name={2},server_type={3},redis_connection={4}]' \ + return '[host={},port={},' \ + 'name={},server_type={},redis_connection={}]' \ .format(self.host, self.port, self.name, @@ -1135,8 +1135,8 @@ def get_node_from_slot(self, slot, read_from_replicas=False, if self.slots_cache.get(slot) is None or \ len(self.slots_cache[slot]) == 0: raise SlotNotCoveredError( - 'Slot "{0}" not covered by the cluster. ' - '"require_full_coverage={1}"'.format( + 'Slot "{}" not covered by the cluster. ' + '"require_full_coverage={}"'.format( slot, self._require_full_coverage) ) @@ -1196,7 +1196,7 @@ def node_require_full_coverage(node): except Exception as e: raise RedisClusterException( 'ERROR sending "config get cluster-require-full-coverage"' - ' command to redis server: {0}, {1}'.format(node.name, e) + ' command to redis server: {}, {}'.format(node.name, e) ) # at least one node should have cluster-require-full-coverage yes @@ -1269,7 +1269,7 @@ def initialize(self): msg = e.__str__ log.exception('An exception occurred while trying to' ' initialize the cluster using the seed node' - ' {0}:\n{1}'.format(startup_node.name, msg)) + ' {}:\n{}'.format(startup_node.name, msg)) continue except ResponseError as e: log.exception( @@ -1283,14 +1283,14 @@ def initialize(self): else: raise RedisClusterException( 'ERROR sending "cluster slots" command to redis ' - 'server: {0}. error: {1}'.format( + 'server: {}. error: {}'.format( startup_node, message) ) except Exception as e: message = e.__str__() raise RedisClusterException( 'ERROR sending "cluster slots" command to redis ' - 'server: {0}. error: {1}'.format( + 'server: {}. error: {}'.format( startup_node, message) ) @@ -1344,14 +1344,14 @@ def initialize(self): # setup if tmp_slots[i][0].name != target_node.name: disagreements.append( - '{0} vs {1} on slot: {2}'.format( + '{} vs {} on slot: {}'.format( tmp_slots[i][0].name, target_node.name, i) ) if len(disagreements) > 5: raise RedisClusterException( 'startup_nodes could not agree on a valid' - ' slots cache: {0}'.format( + ' slots cache: {}'.format( ", ".join(disagreements)) ) @@ -1371,7 +1371,7 @@ def initialize(self): # isn't a full coverage raise RedisClusterException( 'All slots are not covered after query all startup_nodes.' - ' {0} of {1} covered...'.format( + ' {} of {} covered...'.format( len(self.slots_cache), REDIS_CLUSTER_HASH_SLOTS) ) elif not fully_covered and not self._require_full_coverage: @@ -1389,7 +1389,7 @@ def initialize(self): 'cluster-require-full-coverage configuration to no on ' 'all of the cluster nodes if you wish the cluster to ' 'be able to serve without being fully covered.' - ' {0} of {1} covered...'.format( + ' {} of {} covered...'.format( len(self.slots_cache), REDIS_CLUSTER_HASH_SLOTS) ) @@ -1495,7 +1495,7 @@ def _raise_on_invalid_node(self, redis_cluster, node, host, port): """ if node is None or redis_cluster.get_node(node_name=node.name) is None: raise RedisClusterException( - "Node {0}:{1} doesn't exist in the cluster" + "Node {}:{} doesn't exist in the cluster" .format(host, port)) def execute_command(self, *args, **kwargs): @@ -1585,7 +1585,7 @@ def __init__(self, nodes_manager, result_callbacks=None, def __repr__(self): """ """ - return "{0}".format(type(self).__name__) + return f"{type(self).__name__}" def __enter__(self): """ @@ -1813,8 +1813,8 @@ def _send_cluster_commands(self, stack, # if we have more commands to attempt, we've run into problems. # collect all the commands we are allowed to retry. # (MOVED, ASK, or connection errors or timeout errors) - attempt = sorted([c for c in attempt - if isinstance(c.result, ERRORS_ALLOW_RETRY)], + attempt = sorted((c for c in attempt + if isinstance(c.result, ERRORS_ALLOW_RETRY)), key=lambda x: x.position) if attempt and allow_redirections: # RETRY MAGIC HAPPENS HERE! @@ -1848,8 +1848,7 @@ def _send_cluster_commands(self, stack, try: # send each command individually like we # do in the main client. - c.result = super(ClusterPipeline, self). \ - execute_command(*c.args, **c.options) + c.result = super().execute_command(*c.args, **c.options) except RedisError as e: c.result = e @@ -1933,7 +1932,7 @@ def block_pipeline_command(func): def inner(*args, **kwargs): raise RedisClusterException( - "ERROR: Calling pipelined function {0} is blocked when " + "ERROR: Calling pipelined function {} is blocked when " "running redis in cluster mode...".format(func.__name__)) return inner @@ -1977,7 +1976,7 @@ def inner(*args, **kwargs): ClusterPipeline.readonly = block_pipeline_command(RedisCluster.readonly) -class PipelineCommand(object): +class PipelineCommand: """ """ @@ -1992,7 +1991,7 @@ def __init__(self, args, options=None, position=None): self.asking = False -class NodeCommands(object): +class NodeCommands: """ """ diff --git a/redis/commands/cluster.py b/redis/commands/cluster.py index 6c7740d5e9..bf130b120e 100644 --- a/redis/commands/cluster.py +++ b/redis/commands/cluster.py @@ -228,8 +228,8 @@ def client_kill_filter(self, _id=None, _type=None, addr=None, if _type is not None: client_types = ('normal', 'master', 'slave', 'pubsub') if str(_type).lower() not in client_types: - raise DataError("CLIENT KILL type must be one of %r" % ( - client_types,)) + raise DataError("CLIENT KILL type must be one of {!r}".format( + client_types)) args.extend((b'TYPE', _type)) if skipme is not None: if not isinstance(skipme, bool): @@ -267,8 +267,8 @@ def client_list(self, _type=None, target_nodes=None): if _type is not None: client_types = ('normal', 'master', 'replica', 'pubsub') if str(_type).lower() not in client_types: - raise DataError("CLIENT LIST _type must be one of %r" % ( - client_types,)) + raise DataError("CLIENT LIST _type must be one of {!r}".format( + client_types)) return self.execute_command('CLIENT LIST', b'TYPE', _type, @@ -788,7 +788,7 @@ def cluster_failover(self, target_node, option=None): if option: if option.upper() not in ['FORCE', 'TAKEOVER']: raise RedisError( - 'Invalid option for CLUSTER FAILOVER command: {0}'.format( + 'Invalid option for CLUSTER FAILOVER command: {}'.format( option)) else: return self.execute_command('CLUSTER FAILOVER', option, @@ -880,7 +880,7 @@ def cluster_setslot(self, target_node, node_id, slot_id, state): raise RedisError('For "stable" state please use ' 'cluster_setslot_stable') else: - raise RedisError('Invalid slot state: {0}'.format(state)) + raise RedisError(f'Invalid slot state: {state}') def cluster_setslot_stable(self, slot_id): """ diff --git a/redis/commands/core.py b/redis/commands/core.py index 64e3b6d37e..c54e02308c 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -342,8 +342,8 @@ def client_kill_filter(self, _id=None, _type=None, addr=None, if _type is not None: client_types = ('normal', 'master', 'slave', 'pubsub') if str(_type).lower() not in client_types: - raise DataError("CLIENT KILL type must be one of %r" % ( - client_types,)) + raise DataError("CLIENT KILL type must be one of {!r}".format( + client_types)) args.extend((b'TYPE', _type)) if skipme is not None: if not isinstance(skipme, bool): @@ -388,8 +388,8 @@ def client_list(self, _type=None, client_id=[]): if _type is not None: client_types = ('normal', 'master', 'replica', 'pubsub') if str(_type).lower() not in client_types: - raise DataError("CLIENT LIST _type must be one of %r" % ( - client_types,)) + raise DataError("CLIENT LIST _type must be one of {!r}".format( + client_types)) args.append(b'TYPE') args.append(_type) if not isinstance(client_id, list): @@ -1086,7 +1086,7 @@ def getex(self, name, For more information check https://redis.io/commands/getex """ - opset = set([ex, px, exat, pxat]) + opset = {ex, px, exat, pxat} if len(opset) > 2 or len(opset) > 1 and persist: raise DataError("``ex``, ``px``, ``exat``, ``pxat``, " "and ``persist`` are mutually exclusive.") diff --git a/redis/commands/helpers.py b/redis/commands/helpers.py index 5e8ff49d9b..dc5705b80b 100644 --- a/redis/commands/helpers.py +++ b/redis/commands/helpers.py @@ -113,4 +113,4 @@ def quote_string(v): v = v.replace('"', '\\"') - return '"{}"'.format(v) + return f'"{v}"' diff --git a/redis/commands/json/path.py b/redis/commands/json/path.py index 6d87045155..f0a413a00d 100644 --- a/redis/commands/json/path.py +++ b/redis/commands/json/path.py @@ -1,4 +1,4 @@ -class Path(object): +class Path: """This class represents a path in a JSON value.""" strPath = "" diff --git a/redis/commands/parser.py b/redis/commands/parser.py index d8b03271db..9e313cc1f7 100644 --- a/redis/commands/parser.py +++ b/redis/commands/parser.py @@ -46,7 +46,7 @@ def get_keys(self, redis_conn, *args): # version has changed, the commands may not be current self.initialize(redis_conn) if cmd_name not in self.commands: - raise RedisError("{0} command doesn't exist in Redis " + raise RedisError("{} command doesn't exist in Redis " "commands".format(cmd_name.upper())) command = self.commands.get(cmd_name) diff --git a/redis/commands/search/__init__.py b/redis/commands/search/__init__.py index 8320ad4392..a30cebe1b7 100644 --- a/redis/commands/search/__init__.py +++ b/redis/commands/search/__init__.py @@ -7,7 +7,7 @@ class Search(SearchCommands): It abstracts the API of the module and lets you just use the engine. """ - class BatchIndexer(object): + class BatchIndexer: """ A batch indexer allows you to automatically batch document indexing in pipelines, flushing it every N documents. diff --git a/redis/commands/search/aggregation.py b/redis/commands/search/aggregation.py index 3d71329c44..9e8e00aeff 100644 --- a/redis/commands/search/aggregation.py +++ b/redis/commands/search/aggregation.py @@ -1,7 +1,7 @@ FIELDNAME = object() -class Limit(object): +class Limit: def __init__(self, offset=0, count=0): self.offset = offset self.count = count @@ -13,7 +13,7 @@ def build_args(self): return [] -class Reducer(object): +class Reducer: """ Base reducer object for all reducers. @@ -55,7 +55,7 @@ def args(self): return self._args -class SortDirection(object): +class SortDirection: """ This special class is used to indicate sort direction. """ @@ -82,7 +82,7 @@ class Desc(SortDirection): DIRSTRING = "DESC" -class Group(object): +class Group: """ This object automatically created in the `AggregateRequest.group_by()` """ @@ -109,7 +109,7 @@ def build_args(self): return ret -class Projection(object): +class Projection: """ This object automatically created in the `AggregateRequest.apply()` """ @@ -126,7 +126,7 @@ def build_args(self): return ret -class SortBy(object): +class SortBy: """ This object automatically created in the `AggregateRequest.sort_by()` """ @@ -151,7 +151,7 @@ def build_args(self): return ret -class AggregateRequest(object): +class AggregateRequest: """ Aggregation request which can be passed to `Client.aggregate`. """ @@ -370,7 +370,7 @@ def build_args(self): return ret -class Cursor(object): +class Cursor: def __init__(self, cid): self.cid = cid self.max_idle = 0 @@ -385,7 +385,7 @@ def build_args(self): return args -class AggregateResult(object): +class AggregateResult: def __init__(self, rows, cursor, schema): self.rows = rows self.cursor = cursor diff --git a/redis/commands/search/document.py b/redis/commands/search/document.py index 0d4255db17..60afcc10b6 100644 --- a/redis/commands/search/document.py +++ b/redis/commands/search/document.py @@ -1,4 +1,4 @@ -class Document(object): +class Document: """ Represents a single document in a result set """ diff --git a/redis/commands/search/field.py b/redis/commands/search/field.py index 45114a42b7..076c872b62 100644 --- a/redis/commands/search/field.py +++ b/redis/commands/search/field.py @@ -1,4 +1,4 @@ -class Field(object): +class Field: NUMERIC = "NUMERIC" TEXT = "TEXT" diff --git a/redis/commands/search/indexDefinition.py b/redis/commands/search/indexDefinition.py index 4fbc6095c5..4190a48663 100644 --- a/redis/commands/search/indexDefinition.py +++ b/redis/commands/search/indexDefinition.py @@ -8,7 +8,7 @@ class IndexType(Enum): JSON = 2 -class IndexDefinition(object): +class IndexDefinition: """IndexDefinition is used to define a index definition for automatic indexing on Hash or Json update.""" diff --git a/redis/commands/search/query.py b/redis/commands/search/query.py index 85a8255334..5534f7b88e 100644 --- a/redis/commands/search/query.py +++ b/redis/commands/search/query.py @@ -1,4 +1,4 @@ -class Query(object): +class Query: """ Query is used to build complex queries that have more parameters than just the query string. The query string is set in the constructor, and other @@ -291,7 +291,7 @@ def expander(self, expander): return self -class Filter(object): +class Filter: def __init__(self, keyword, field, *args): self.args = [keyword, field] + list(args) @@ -303,8 +303,8 @@ class NumericFilter(Filter): def __init__(self, field, minval, maxval, minExclusive=False, maxExclusive=False): args = [ - minval if not minExclusive else "({}".format(minval), - maxval if not maxExclusive else "({}".format(maxval), + minval if not minExclusive else f"({minval}", + maxval if not maxExclusive else f"({maxval}", ] Filter.__init__(self, "FILTER", field, *args) @@ -320,6 +320,6 @@ def __init__(self, field, lon, lat, radius, unit=KILOMETERS): Filter.__init__(self, "GEOFILTER", field, lon, lat, radius, unit) -class SortbyField(object): +class SortbyField: def __init__(self, field, asc=True): self.args = [field, "ASC" if asc else "DESC"] diff --git a/redis/commands/search/querystring.py b/redis/commands/search/querystring.py index aecd3b82f5..969b06bcbe 100644 --- a/redis/commands/search/querystring.py +++ b/redis/commands/search/querystring.py @@ -61,7 +61,7 @@ def geo(lat, lon, radius, unit="km"): return GeoValue(lat, lon, radius, unit) -class Value(object): +class Value: @property def combinable(self): """ @@ -134,7 +134,7 @@ def __init__(self, lon, lat, radius, unit="km"): self.unit = unit -class Node(object): +class Node: def __init__(self, *children, **kwparams): """ Create a node @@ -197,7 +197,7 @@ def __init__(self, *children, **kwparams): def join_fields(self, key, vals): if len(vals) == 1: - return [BaseNode("@{}:{}".format(key, vals[0].to_string()))] + return [BaseNode(f"@{key}:{vals[0].to_string()}")] if not vals[0].combinable: return [BaseNode("@{}:{}".format(key, v.to_string())) for v in vals] @@ -235,7 +235,7 @@ def __str__(self): class BaseNode(Node): def __init__(self, s): - super(BaseNode, self).__init__() + super().__init__() self.s = str(s) def to_string(self, with_parens=None): @@ -268,7 +268,7 @@ class DisjunctNode(IntersectNode): def to_string(self, with_parens=None): with_parens = self._should_use_paren(with_parens) - ret = super(DisjunctNode, self).to_string(with_parens=False) + ret = super().to_string(with_parens=False) if with_parens: return "(-" + ret + ")" else: @@ -294,7 +294,7 @@ class OptionalNode(IntersectNode): def to_string(self, with_parens=None): with_parens = self._should_use_paren(with_parens) - ret = super(OptionalNode, self).to_string(with_parens=False) + ret = super().to_string(with_parens=False) if with_parens: return "(~" + ret + ")" else: diff --git a/redis/commands/search/reducers.py b/redis/commands/search/reducers.py index 6cbbf2f355..41ed11a238 100644 --- a/redis/commands/search/reducers.py +++ b/redis/commands/search/reducers.py @@ -3,7 +3,7 @@ class FieldOnlyReducer(Reducer): def __init__(self, field): - super(FieldOnlyReducer, self).__init__(field) + super().__init__(field) self._field = field @@ -15,7 +15,7 @@ class count(Reducer): NAME = "COUNT" def __init__(self): - super(count, self).__init__() + super().__init__() class sum(FieldOnlyReducer): @@ -26,7 +26,7 @@ class sum(FieldOnlyReducer): NAME = "SUM" def __init__(self, field): - super(sum, self).__init__(field) + super().__init__(field) class min(FieldOnlyReducer): @@ -37,7 +37,7 @@ class min(FieldOnlyReducer): NAME = "MIN" def __init__(self, field): - super(min, self).__init__(field) + super().__init__(field) class max(FieldOnlyReducer): @@ -48,7 +48,7 @@ class max(FieldOnlyReducer): NAME = "MAX" def __init__(self, field): - super(max, self).__init__(field) + super().__init__(field) class avg(FieldOnlyReducer): @@ -59,7 +59,7 @@ class avg(FieldOnlyReducer): NAME = "AVG" def __init__(self, field): - super(avg, self).__init__(field) + super().__init__(field) class tolist(FieldOnlyReducer): @@ -70,7 +70,7 @@ class tolist(FieldOnlyReducer): NAME = "TOLIST" def __init__(self, field): - super(tolist, self).__init__(field) + super().__init__(field) class count_distinct(FieldOnlyReducer): @@ -82,7 +82,7 @@ class count_distinct(FieldOnlyReducer): NAME = "COUNT_DISTINCT" def __init__(self, field): - super(count_distinct, self).__init__(field) + super().__init__(field) class count_distinctish(FieldOnlyReducer): @@ -104,7 +104,7 @@ class quantile(Reducer): NAME = "QUANTILE" def __init__(self, field, pct): - super(quantile, self).__init__(field, str(pct)) + super().__init__(field, str(pct)) self._field = field @@ -116,7 +116,7 @@ class stddev(FieldOnlyReducer): NAME = "STDDEV" def __init__(self, field): - super(stddev, self).__init__(field) + super().__init__(field) class first_value(Reducer): @@ -155,7 +155,7 @@ def __init__(self, field, *byfields): args = [field] if fieldstrs: args += ["BY"] + fieldstrs - super(first_value, self).__init__(*args) + super().__init__(*args) self._field = field @@ -174,5 +174,5 @@ def __init__(self, field, size): **size**: Return this many items (can be less) """ args = [field, str(size)] - super(random_sample, self).__init__(*args) + super().__init__(*args) self._field = field diff --git a/redis/commands/search/result.py b/redis/commands/search/result.py index 9cd922ac1d..a799395777 100644 --- a/redis/commands/search/result.py +++ b/redis/commands/search/result.py @@ -2,7 +2,7 @@ from ._util import to_string -class Result(object): +class Result: """ Represents the result of a search query, and has an array of Document objects diff --git a/redis/commands/search/suggestion.py b/redis/commands/search/suggestion.py index 3401af94eb..6d295a652f 100644 --- a/redis/commands/search/suggestion.py +++ b/redis/commands/search/suggestion.py @@ -1,7 +1,7 @@ from ._util import to_string -class Suggestion(object): +class Suggestion: """ Represents a single suggestion being sent or returned from the autocomplete server @@ -16,7 +16,7 @@ def __repr__(self): return self.string -class SuggestionParser(object): +class SuggestionParser: """ Internal class used to parse results from the `SUGGET` command. This needs to consume either 1, 2, or 3 values at a time from diff --git a/redis/commands/timeseries/info.py b/redis/commands/timeseries/info.py index 3b89503f18..2b8acd1b66 100644 --- a/redis/commands/timeseries/info.py +++ b/redis/commands/timeseries/info.py @@ -2,7 +2,7 @@ from ..helpers import nativestr -class TSInfo(object): +class TSInfo: """ Hold information and statistics on the time-series. Can be created using ``tsinfo`` command diff --git a/redis/connection.py b/redis/connection.py index 6ff3650805..18258a90f6 100755 --- a/redis/connection.py +++ b/redis/connection.py @@ -538,8 +538,8 @@ def __init__(self, host='localhost', port=6379, db=0, password=None, self._buffer_cutoff = 6000 def __repr__(self): - repr_args = ','.join(['%s=%s' % (k, v) for k, v in self.repr_pieces()]) - return '%s<%s>' % (self.__class__.__name__, repr_args) + repr_args = ','.join([f'{k}={v}' for k, v in self.repr_pieces()]) + return f'{self.__class__.__name__}<{repr_args}>' def repr_pieces(self): pieces = [ @@ -579,7 +579,7 @@ def connect(self): sock = self._connect() except socket.timeout: raise TimeoutError("Timeout connecting to server") - except socket.error as e: + except OSError as e: raise ConnectionError(self._error_message(e)) self._sock = sock @@ -734,7 +734,7 @@ def send_packed_command(self, command, check_health=True): except socket.timeout: self.disconnect() raise TimeoutError("Timeout writing to socket") - except socket.error as e: + except OSError as e: self.disconnect() if len(e.args) == 1: errno, errmsg = 'UNKNOWN', e.args[0] @@ -769,7 +769,7 @@ def read_response(self, disable_decoding=False): self.disconnect() raise TimeoutError("Timeout reading from %s:%s" % (self.host, self.port)) - except socket.error as e: + except OSError as e: self.disconnect() raise ConnectionError("Error while reading from %s:%s : %s" % (self.host, self.port, e.args)) @@ -1109,7 +1109,7 @@ def __init__(self, connection_class=Connection, max_connections=None, self.reset() def __repr__(self): - return "%s<%s>" % ( + return "{}<{}>".format( type(self).__name__, repr(self.connection_class(**self.connection_kwargs)), ) diff --git a/redis/sentinel.py b/redis/sentinel.py index 3efd58fa39..232500868d 100644 --- a/redis/sentinel.py +++ b/redis/sentinel.py @@ -24,9 +24,9 @@ def __init__(self, **kwargs): def __repr__(self): pool = self.connection_pool - s = '%s' % (type(self).__name__, pool.service_name) + s = f'{type(self).__name__}' if self.host: - host_info = ',host=%s,port=%s' % (self.host, self.port) + host_info = f',host={self.host},port={self.port}' s = s % host_info return s @@ -91,7 +91,7 @@ def __init__(self, service_name, sentinel_manager, **kwargs): self.sentinel_manager = sentinel_manager def __repr__(self): - return "%s' % ( + return '{}'.format( type(self).__name__, ','.join(sentinel_addresses)) @@ -240,7 +240,7 @@ def discover_master(self, service_name): self.sentinels[0], self.sentinels[sentinel_no] = ( sentinel, self.sentinels[0]) return state['ip'], state['port'] - raise MasterNotFoundError("No master found for %r" % (service_name,)) + raise MasterNotFoundError(f"No master found for {service_name!r}") def filter_slaves(self, slaves): "Remove slaves that are in an ODOWN or SDOWN state" diff --git a/tasks.py b/tasks.py index e4821949d8..07914e547c 100644 --- a/tasks.py +++ b/tasks.py @@ -16,7 +16,7 @@ def devenv(c): clean(c) cmd = 'tox -e devenv' for d in dockers: - cmd += " --docker-dont-stop={}".format(d) + cmd += f" --docker-dont-stop={d}" run(cmd) diff --git a/tests/conftest.py b/tests/conftest.py index ddc0834037..0c9e3aaaff 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -102,8 +102,8 @@ def wait_for_cluster_creation(redis_url, cluster_nodes, timeout=20): if now >= end_time: available_nodes = 0 if client is None else len(client.get_nodes()) raise RedisClusterException( - "The cluster did not become available after {0} seconds. " - "Only {1} nodes out of {2} are available".format( + "The cluster did not become available after {} seconds. " + "Only {} nodes out of {} are available".format( timeout, available_nodes, cluster_nodes)) @@ -112,7 +112,7 @@ def skip_if_server_version_lt(min_version): check = LooseVersion(redis_version) < LooseVersion(min_version) return pytest.mark.skipif( check, - reason="Redis version required >= {}".format(min_version)) + reason=f"Redis version required >= {min_version}") def skip_if_server_version_gte(min_version): @@ -120,12 +120,12 @@ def skip_if_server_version_gte(min_version): check = LooseVersion(redis_version) >= LooseVersion(min_version) return pytest.mark.skipif( check, - reason="Redis version required < {}".format(min_version)) + reason=f"Redis version required < {min_version}") def skip_unless_arch_bits(arch_bits): return pytest.mark.skipif(REDIS_INFO["arch_bits"] != arch_bits, - reason="server is not {}-bit".format(arch_bits)) + reason=f"server is not {arch_bits}-bit") def skip_ifmodversion_lt(min_version: str, module_name: str): @@ -144,7 +144,7 @@ def skip_ifmodversion_lt(min_version: str, module_name: str): check = version < mv return pytest.mark.skipif(check, reason="Redis module version") - raise AttributeError("No redis module named {}".format(module_name)) + raise AttributeError(f"No redis module named {module_name}") def skip_if_redis_enterprise(func): diff --git a/tests/test_cluster.py b/tests/test_cluster.py index 071cb7d2f1..ac223b759d 100644 --- a/tests/test_cluster.py +++ b/tests/test_cluster.py @@ -178,7 +178,7 @@ def ok_response(connection, *args, **options): return "MOCK_OK" parse_response.side_effect = ok_response - raise MovedError("{0} {1}:{2}".format(slot, r_host, r_port)) + raise MovedError(f"{slot} {r_host}:{r_port}") parse_response.side_effect = moved_redirect_effect assert rc.execute_command("SET", "foo", "bar") == "MOCK_OK" @@ -229,7 +229,7 @@ def test_empty_startup_nodes(self): "cluster"), str_if_bytes(ex.value) def test_from_url(self, r): - redis_url = "redis://{0}:{1}/0".format(default_host, default_port) + redis_url = f"redis://{default_host}:{default_port}/0" with patch.object(RedisCluster, 'from_url') as from_url: def from_url_mocked(_url, **_kwargs): return get_mocked_redis_client(url=_url, **_kwargs) @@ -333,7 +333,7 @@ def ok_response(connection, *args, **options): return "MOCK_OK" parse_response.side_effect = ok_response - raise AskError("12182 {0}:{1}".format(redirect_node.host, + raise AskError("12182 {}:{}".format(redirect_node.host, redirect_node.port)) parse_response.side_effect = ask_redirect_effect @@ -498,14 +498,14 @@ def test_keyslot(self, r): assert r.keyslot(125) == r.keyslot(b"125") assert r.keyslot(125) == r.keyslot("\x31\x32\x35") assert r.keyslot("大奖") == r.keyslot(b"\xe5\xa4\xa7\xe5\xa5\x96") - assert r.keyslot(u"大奖") == r.keyslot(b"\xe5\xa4\xa7\xe5\xa5\x96") + assert r.keyslot("大奖") == r.keyslot(b"\xe5\xa4\xa7\xe5\xa5\x96") assert r.keyslot(1337.1234) == r.keyslot("1337.1234") assert r.keyslot(1337) == r.keyslot("1337") assert r.keyslot(b"abc") == r.keyslot("abc") def test_get_node_name(self): assert get_node_name(default_host, default_port) == \ - "{0}:{1}".format(default_host, default_port) + f"{default_host}:{default_port}" def test_all_nodes(self, r): """ @@ -713,7 +713,7 @@ def test_pubsub_channels_merge_results(self, r): pubsub_nodes = [] i = 0 for node in nodes: - channel = "foo{0}".format(i) + channel = f"foo{i}" # We will create different pubsub clients where each one is # connected to a different node p = r.pubsub(node) @@ -1180,8 +1180,7 @@ def test_client_kill(self, r, r2): clients = [client for client in r.client_list(target_nodes=node) if client.get('name') in ['redis-py-c1', 'redis-py-c2']] assert len(clients) == 2 - clients_by_name = dict([(client.get('name'), client) - for client in clients]) + clients_by_name = {client.get('name'): client for client in clients} client_addr = clients_by_name['redis-py-c2'].get('addr') assert r.client_kill(client_addr, target_nodes=node) is True @@ -2374,7 +2373,7 @@ def test_asking_error(self, r): warnings.warn("skipping this test since the cluster has only one " "node") return - ask_msg = "{0} {1}:{2}".format(r.keyslot(key), ask_node.host, + ask_msg = "{} {}:{}".format(r.keyslot(key), ask_node.host, ask_node.port) def raise_ask_error(): @@ -2435,7 +2434,7 @@ def test_moved_redirection_on_slave_with_default(self, r): with r.pipeline() as readwrite_pipe: mock_node_resp(primary, "MOCK_FOO") if replica is not None: - moved_error = "{0} {1}:{2}".format(r.keyslot(key), + moved_error = "{} {}:{}".format(r.keyslot(key), primary.host, primary.port) diff --git a/tests/test_commands.py b/tests/test_commands.py index f526ae5dd6..f927feeb51 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -35,7 +35,7 @@ def cleanup(): def redis_server_time(client): seconds, milliseconds = client.time() - timestamp = float('%s.%s' % (seconds, milliseconds)) + timestamp = float(f'{seconds}.{milliseconds}') return datetime.datetime.fromtimestamp(timestamp) @@ -162,11 +162,11 @@ def teardown(): commands=['+get', '+mget', '-hset'], keys=['cache:*', 'objects:*']) acl = r.acl_getuser(username) - assert set(acl['categories']) == set(['-@all', '+@set', '+@hash']) - assert set(acl['commands']) == set(['+get', '+mget', '-hset']) + assert set(acl['categories']) == {'-@all', '+@set', '+@hash'} + assert set(acl['commands']) == {'+get', '+mget', '-hset'} assert acl['enabled'] is True assert 'on' in acl['flags'] - assert set(acl['keys']) == set([b'cache:*', b'objects:*']) + assert set(acl['keys']) == {b'cache:*', b'objects:*'} assert len(acl['passwords']) == 2 # test reset=False keeps existing ACL and applies new ACL on top @@ -181,11 +181,11 @@ def teardown(): commands=['+mget'], keys=['objects:*']) acl = r.acl_getuser(username) - assert set(acl['categories']) == set(['-@all', '+@set', '+@hash']) - assert set(acl['commands']) == set(['+get', '+mget']) + assert set(acl['categories']) == {'-@all', '+@set', '+@hash'} + assert set(acl['commands']) == {'+get', '+mget'} assert acl['enabled'] is True assert 'on' in acl['flags'] - assert set(acl['keys']) == set([b'cache:*', b'objects:*']) + assert set(acl['keys']) == {b'cache:*', b'objects:*'} assert len(acl['passwords']) == 2 # test removal of passwords @@ -405,8 +405,7 @@ def test_client_kill(self, r, r2): if client.get('name') in ['redis-py-c1', 'redis-py-c2']] assert len(clients) == 2 - clients_by_name = dict([(client.get('name'), client) - for client in clients]) + clients_by_name = {client.get('name'): client for client in clients} client_addr = clients_by_name['redis-py-c2'].get('addr') assert r.client_kill(client_addr) is True @@ -439,8 +438,7 @@ def test_client_kill_filter_by_id(self, r, r2): if client.get('name') in ['redis-py-c1', 'redis-py-c2']] assert len(clients) == 2 - clients_by_name = dict([(client.get('name'), client) - for client in clients]) + clients_by_name = {client.get('name'): client for client in clients} client_2_id = clients_by_name['redis-py-c2'].get('id') resp = r.client_kill_filter(_id=client_2_id) @@ -460,8 +458,7 @@ def test_client_kill_filter_by_addr(self, r, r2): if client.get('name') in ['redis-py-c1', 'redis-py-c2']] assert len(clients) == 2 - clients_by_name = dict([(client.get('name'), client) - for client in clients]) + clients_by_name = {client.get('name'): client for client in clients} client_2_addr = clients_by_name['redis-py-c2'].get('addr') resp = r.client_kill_filter(addr=client_2_addr) @@ -487,8 +484,7 @@ def test_client_kill_filter_by_laddr(self, r, r2): if client.get('name') in ['redis-py-c1', 'redis-py-c2']] assert len(clients) == 2 - clients_by_name = dict([(client.get('name'), client) - for client in clients]) + clients_by_name = {client.get('name'): client for client in clients} client_2_addr = clients_by_name['redis-py-c2'].get('laddr') assert r.client_kill_filter(laddr=client_2_addr) diff --git a/tests/test_search.py b/tests/test_search.py index b65ac8dcbf..c7b570cdd1 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -99,7 +99,7 @@ def createIndex(client, num_docs=100, definition=None): play, chapter, _, text = \ line[1], line[2], line[4], line[5] - key = "{}:{}".format(play, chapter).lower() + key = f"{play}:{chapter}".lower() d = chapters.setdefault(key, {}) d["play"] = play d["txt"] = d.get("txt", "") + " " + text @@ -861,7 +861,7 @@ def test_phonetic_matcher(client): res = client.ft().search(Query("Jon")) assert 2 == len(res.docs) - assert ["John", "Jon"] == sorted([d.name for d in res.docs]) + assert ["John", "Jon"] == sorted(d.name for d in res.docs) @pytest.mark.redismod diff --git a/tests/test_timeseries.py b/tests/test_timeseries.py index c0fb09e226..07433574f1 100644 --- a/tests/test_timeseries.py +++ b/tests/test_timeseries.py @@ -31,7 +31,7 @@ def test_create(client): def test_create_duplicate_policy(client): # Test for duplicate policy for duplicate_policy in ["block", "last", "first", "min", "max"]: - ts_name = "time-serie-ooo-{0}".format(duplicate_policy) + ts_name = f"time-serie-ooo-{duplicate_policy}" assert client.ts().create(ts_name, duplicate_policy=duplicate_policy) info = client.ts().info(ts_name) assert duplicate_policy == info.duplicate_policy From 5f69be112edafbe8ebec6f5963b687307f89b289 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 29 Nov 2021 13:59:04 +0200 Subject: [PATCH 2/5] Run flynt --- benchmarks/base.py | 4 ++-- benchmarks/command_packer_benchmark.py | 6 ++---- redis/client.py | 8 +++----- redis/cluster.py | 9 +++------ redis/commands/cluster.py | 11 ++++------- redis/commands/core.py | 10 ++++------ redis/commands/search/commands.py | 2 +- redis/commands/search/document.py | 2 +- redis/commands/search/indexDefinition.py | 3 +-- redis/commands/search/querystring.py | 10 +++------- redis/connection.py | 25 +++++++++--------------- redis/sentinel.py | 2 +- tasks.py | 2 +- tests/conftest.py | 7 +++---- tests/test_cluster.py | 10 +++------- tests/test_commands.py | 4 ++-- tests/test_connection.py | 2 +- tests/test_multiprocessing.py | 7 ++----- tests/test_pipeline.py | 2 +- tests/test_pubsub.py | 2 +- 20 files changed, 48 insertions(+), 80 deletions(-) diff --git a/benchmarks/base.py b/benchmarks/base.py index 029f504a5e..519c9ccab5 100644 --- a/benchmarks/base.py +++ b/benchmarks/base.py @@ -35,11 +35,11 @@ def run_benchmark(self): for value_set in itertools.product(*group_values): pairs = list(zip(group_names, value_set)) arg_string = ', '.join(f'{p[0]}={p[1]}' for p in pairs) - sys.stdout.write('Benchmark: %s... ' % arg_string) + sys.stdout.write(f'Benchmark: {arg_string}... ') sys.stdout.flush() kwargs = dict(pairs) setup = functools.partial(self.setup, **kwargs) run = functools.partial(self.run, **kwargs) t = timeit.timeit(stmt=run, setup=setup, number=1000) - sys.stdout.write('%f\n' % t) + sys.stdout.write(f'{t:f}\n') sys.stdout.flush() diff --git a/benchmarks/command_packer_benchmark.py b/benchmarks/command_packer_benchmark.py index 978066ddd6..3176c06800 100644 --- a/benchmarks/command_packer_benchmark.py +++ b/benchmarks/command_packer_benchmark.py @@ -16,8 +16,7 @@ def send_packed_command(self, command, check_health=True): _errno, errmsg = 'UNKNOWN', e.args[0] else: _errno, errmsg = e.args - raise ConnectionError("Error %s while writing to socket. %s." % - (_errno, errmsg)) + raise ConnectionError(f"Error {_errno} while writing to socket. {errmsg}.") except Exception: self.disconnect() raise @@ -48,8 +47,7 @@ def send_packed_command(self, command, check_health=True): _errno, errmsg = 'UNKNOWN', e.args[0] else: _errno, errmsg = e.args - raise ConnectionError("Error %s while writing to socket. %s." % - (_errno, errmsg)) + raise ConnectionError(f"Error {_errno} while writing to socket. {errmsg}.") except Exception: self.disconnect() raise diff --git a/redis/client.py b/redis/client.py index 107072d3ab..2e4c18ba08 100755 --- a/redis/client.py +++ b/redis/client.py @@ -1141,7 +1141,7 @@ def __enter__(self): # check that monitor returns 'OK', but don't return it to user response = self.connection.read_response() if not bool_ok(response): - raise RedisError('MONITOR failed: %s' % response) + raise RedisError(f'MONITOR failed: {response}') return self def __exit__(self, *args): @@ -1517,12 +1517,10 @@ def run_in_thread(self, sleep_time=0, daemon=False, exception_handler=None): for channel, handler in self.channels.items(): if handler is None: - raise PubSubError("Channel: '%s' has no handler registered" % - channel) + raise PubSubError(f"Channel: '{channel}' has no handler registered") for pattern, handler in self.patterns.items(): if handler is None: - raise PubSubError("Pattern: '%s' has no handler registered" % - pattern) + raise PubSubError(f"Pattern: '{pattern}' has no handler registered") thread = PubSubWorkerThread( self, diff --git a/redis/cluster.py b/redis/cluster.py index 9f37a65c37..40a69197ed 100644 --- a/redis/cluster.py +++ b/redis/cluster.py @@ -678,8 +678,7 @@ def _determine_nodes(self, *args, **kwargs): # get the nodes group for this command if it was predefined command_flag = self.command_flags.get(command) if command_flag: - log.debug("Target node/s for {0}: {1}". - format(command, command_flag)) + log.debug(f"Target node/s for {command}: {command_flag}") if command_flag == self.__class__.RANDOM: # return a random node return [self.get_random_node()] @@ -824,8 +823,7 @@ def execute_command(self, *args, **kwargs): *args, **kwargs, nodes_flag=target_nodes) if not target_nodes: raise RedisClusterException( - "No targets were found to execute" - " {} command on".format(args)) + f"No targets were found to execute {args} command on") for node in target_nodes: res[node.name] = self._execute_command( node, *args, **kwargs) @@ -1495,8 +1493,7 @@ def _raise_on_invalid_node(self, redis_cluster, node, host, port): """ if node is None or redis_cluster.get_node(node_name=node.name) is None: raise RedisClusterException( - "Node {}:{} doesn't exist in the cluster" - .format(host, port)) + f"Node {host}:{port} doesn't exist in the cluster") def execute_command(self, *args, **kwargs): """ diff --git a/redis/commands/cluster.py b/redis/commands/cluster.py index bf130b120e..be77207a96 100644 --- a/redis/commands/cluster.py +++ b/redis/commands/cluster.py @@ -228,8 +228,7 @@ def client_kill_filter(self, _id=None, _type=None, addr=None, if _type is not None: client_types = ('normal', 'master', 'slave', 'pubsub') if str(_type).lower() not in client_types: - raise DataError("CLIENT KILL type must be one of {!r}".format( - client_types)) + raise DataError(f"CLIENT KILL type must be one of {client_types!r}") args.extend((b'TYPE', _type)) if skipme is not None: if not isinstance(skipme, bool): @@ -267,8 +266,7 @@ def client_list(self, _type=None, target_nodes=None): if _type is not None: client_types = ('normal', 'master', 'replica', 'pubsub') if str(_type).lower() not in client_types: - raise DataError("CLIENT LIST _type must be one of {!r}".format( - client_types)) + raise DataError(f"CLIENT LIST _type must be one of {client_types!r}") return self.execute_command('CLIENT LIST', b'TYPE', _type, @@ -302,7 +300,7 @@ def client_reply(self, reply, target_nodes=None): """ replies = ['ON', 'OFF', 'SKIP'] if reply not in replies: - raise DataError('CLIENT REPLY must be one of %r' % replies) + raise DataError(f'CLIENT REPLY must be one of {replies!r}') return self.execute_command("CLIENT REPLY", reply, target_nodes=target_nodes) @@ -788,8 +786,7 @@ def cluster_failover(self, target_node, option=None): if option: if option.upper() not in ['FORCE', 'TAKEOVER']: raise RedisError( - 'Invalid option for CLUSTER FAILOVER command: {}'.format( - option)) + f'Invalid option for CLUSTER FAILOVER command: {option}') else: return self.execute_command('CLUSTER FAILOVER', option, target_nodes=target_node) diff --git a/redis/commands/core.py b/redis/commands/core.py index c54e02308c..08210b23df 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -342,8 +342,7 @@ def client_kill_filter(self, _id=None, _type=None, addr=None, if _type is not None: client_types = ('normal', 'master', 'slave', 'pubsub') if str(_type).lower() not in client_types: - raise DataError("CLIENT KILL type must be one of {!r}".format( - client_types)) + raise DataError(f"CLIENT KILL type must be one of {client_types!r}") args.extend((b'TYPE', _type)) if skipme is not None: if not isinstance(skipme, bool): @@ -388,8 +387,7 @@ def client_list(self, _type=None, client_id=[]): if _type is not None: client_types = ('normal', 'master', 'replica', 'pubsub') if str(_type).lower() not in client_types: - raise DataError("CLIENT LIST _type must be one of {!r}".format( - client_types)) + raise DataError(f"CLIENT LIST _type must be one of {client_types!r}") args.append(b'TYPE') args.append(_type) if not isinstance(client_id, list): @@ -434,7 +432,7 @@ def client_reply(self, reply): """ replies = ['ON', 'OFF', 'SKIP'] if reply not in replies: - raise DataError('CLIENT REPLY must be one of %r' % replies) + raise DataError(f'CLIENT REPLY must be one of {replies!r}') return self.execute_command("CLIENT REPLY", reply) def client_id(self): @@ -551,7 +549,7 @@ def config_rewrite(self): return self.execute_command('CONFIG REWRITE') def cluster(self, cluster_arg, *args): - return self.execute_command('CLUSTER %s' % cluster_arg.upper(), *args) + return self.execute_command(f'CLUSTER {cluster_arg.upper()}', *args) def dbsize(self): """ diff --git a/redis/commands/search/commands.py b/redis/commands/search/commands.py index ed58255fec..c19cb93e53 100644 --- a/redis/commands/search/commands.py +++ b/redis/commands/search/commands.py @@ -348,7 +348,7 @@ def _mk_query_args(self, query): # convert the query from a text to a query object query = Query(query) if not isinstance(query, Query): - raise ValueError("Bad query type %s" % type(query)) + raise ValueError(f"Bad query type {type(query)}") args += query.get_args() return args, query diff --git a/redis/commands/search/document.py b/redis/commands/search/document.py index 60afcc10b6..5b3050545a 100644 --- a/redis/commands/search/document.py +++ b/redis/commands/search/document.py @@ -10,4 +10,4 @@ def __init__(self, id, payload=None, **fields): setattr(self, k, v) def __repr__(self): - return "Document %s" % self.__dict__ + return f"Document {self.__dict__}" diff --git a/redis/commands/search/indexDefinition.py b/redis/commands/search/indexDefinition.py index 4190a48663..0c7a3b0635 100644 --- a/redis/commands/search/indexDefinition.py +++ b/redis/commands/search/indexDefinition.py @@ -38,8 +38,7 @@ def _appendIndexType(self, index_type): elif index_type is IndexType.JSON: self.args.extend(["ON", "JSON"]) elif index_type is not None: - raise RuntimeError("index_type must be one of {}". - format(list(IndexType))) + raise RuntimeError(f"index_type must be one of {list(IndexType)}") def _appendPrefix(self, prefix): """Append PREFIX.""" diff --git a/redis/commands/search/querystring.py b/redis/commands/search/querystring.py index 969b06bcbe..ffba542e31 100644 --- a/redis/commands/search/querystring.py +++ b/redis/commands/search/querystring.py @@ -199,11 +199,9 @@ def join_fields(self, key, vals): if len(vals) == 1: return [BaseNode(f"@{key}:{vals[0].to_string()}")] if not vals[0].combinable: - return [BaseNode("@{}:{}".format(key, - v.to_string())) for v in vals] + return [BaseNode(f"@{key}:{v.to_string()}") for v in vals] s = BaseNode( - "@{}:({})".format(key, - self.JOINSTR.join(v.to_string() for v in vals)) + f"@{key}:({self.JOINSTR.join(v.to_string() for v in vals)})" ) return [s] @@ -220,9 +218,7 @@ def JOINSTR(self): def to_string(self, with_parens=None): with_parens = self._should_use_paren(with_parens) pre, post = ("(", ")") if with_parens else ("", "") - return "{}{}{}".format( - pre, self.JOINSTR.join(n.to_string() for n in self.params), post - ) + return f"{pre}{self.JOINSTR.join(n.to_string() for n in self.params)}{post}" def _should_use_paren(self, optval): if optval is not None: diff --git a/redis/connection.py b/redis/connection.py index 18258a90f6..07486a9289 100755 --- a/redis/connection.py +++ b/redis/connection.py @@ -214,8 +214,7 @@ def _read_from_socket(self, length=None, timeout=SENTINEL, allowed = NONBLOCKING_EXCEPTION_ERROR_NUMBERS.get(ex.__class__, -1) if not raise_on_timeout and ex.errno == allowed: return False - raise ConnectionError("Error while reading from socket: %s" % - (ex.args,)) + raise ConnectionError(f"Error while reading from socket: {ex.args}") finally: if custom_timeout: sock.settimeout(self.socket_timeout) @@ -323,7 +322,7 @@ def read_response(self, disable_decoding=False): byte, response = raw[:1], raw[1:] if byte not in (b'-', b'+', b':', b'$', b'*'): - raise InvalidResponse("Protocol Error: %r" % raw) + raise InvalidResponse(f"Protocol Error: {raw!r}") # server returned an error if byte == b'-': @@ -445,8 +444,7 @@ def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True): allowed = NONBLOCKING_EXCEPTION_ERROR_NUMBERS.get(ex.__class__, -1) if not raise_on_timeout and ex.errno == allowed: return False - raise ConnectionError("Error while reading from socket: %s" % - (ex.args,)) + raise ConnectionError(f"Error while reading from socket: {ex.args}") finally: if custom_timeout: sock.settimeout(self._socket_timeout) @@ -646,8 +644,7 @@ def _error_message(self, exception): # args for socket.error can either be (errno, "message") # or just "message" if len(exception.args) == 1: - return "Error connecting to %s:%s. %s." % \ - (self.host, self.port, exception.args[0]) + return f"Error connecting to {self.host}:{self.port}. {exception.args[0]}." else: return "Error %s connecting to %s:%s. %s." % \ (exception.args[0], self.host, self.port, exception.args[1]) @@ -741,8 +738,7 @@ def send_packed_command(self, command, check_health=True): else: errno = e.args[0] errmsg = e.args[1] - raise ConnectionError("Error %s while writing to socket. %s." % - (errno, errmsg)) + raise ConnectionError(f"Error {errno} while writing to socket. {errmsg}.") except BaseException: self.disconnect() raise @@ -767,8 +763,7 @@ def read_response(self, disable_decoding=False): ) except socket.timeout: self.disconnect() - raise TimeoutError("Timeout reading from %s:%s" % - (self.host, self.port)) + raise TimeoutError(f"Timeout reading from {self.host}:{self.port}") except OSError as e: self.disconnect() raise ConnectionError("Error while reading from %s:%s : %s" % @@ -867,8 +862,7 @@ def __init__(self, ssl_keyfile=None, ssl_certfile=None, } if ssl_cert_reqs not in CERT_REQS: raise RedisError( - "Invalid SSL Certificate Requirements Flag: %s" % - ssl_cert_reqs) + f"Invalid SSL Certificate Requirements Flag: {ssl_cert_reqs}") ssl_cert_reqs = CERT_REQS[ssl_cert_reqs] self.cert_reqs = ssl_cert_reqs self.ca_certs = ssl_ca_certs @@ -947,8 +941,7 @@ def _error_message(self, exception): # args for socket.error can either be (errno, "message") # or just "message" if len(exception.args) == 1: - return "Error connecting to unix socket: %s. %s." % \ - (self.path, exception.args[0]) + return f"Error connecting to unix socket: {self.path}. {exception.args[0]}." else: return "Error %s connecting to unix socket: %s. %s." % \ (exception.args[0], self.path, exception.args[1]) @@ -990,7 +983,7 @@ def parse_url(url): kwargs[name] = parser(value) except (TypeError, ValueError): raise ValueError( - "Invalid value for `%s` in connection URL." % name + f"Invalid value for `{name}` in connection URL." ) else: kwargs[name] = value diff --git a/redis/sentinel.py b/redis/sentinel.py index 232500868d..e4caa0fe7c 100644 --- a/redis/sentinel.py +++ b/redis/sentinel.py @@ -136,7 +136,7 @@ def rotate_slaves(self): yield self.get_master_address() except MasterNotFoundError: pass - raise SlaveNotFoundError('No slave found for %r' % (self.service_name)) + raise SlaveNotFoundError(f'No slave found for {self.service_name!r}') class Sentinel(SentinelCommands): diff --git a/tasks.py b/tasks.py index 07914e547c..8d9c4c64be 100644 --- a/tasks.py +++ b/tasks.py @@ -73,7 +73,7 @@ def clean(c): shutil.rmtree("build") if os.path.isdir("dist"): shutil.rmtree("dist") - run("docker rm -f {}".format(' '.join(dockers))) + run(f"docker rm -f {' '.join(dockers)}") @task diff --git a/tests/conftest.py b/tests/conftest.py index 0c9e3aaaff..e401575f6c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -87,8 +87,7 @@ def wait_for_cluster_creation(redis_url, cluster_nodes, timeout=20): now = time.time() end_time = now + timeout client = None - print("Waiting for {0} cluster nodes to become available". - format(cluster_nodes)) + print(f"Waiting for {cluster_nodes} cluster nodes to become available") while now < end_time: try: client = redis.RedisCluster.from_url(redis_url) @@ -320,8 +319,8 @@ def wait_for_command(client, monitor, command): if LooseVersion(redis_version) >= LooseVersion('5.0.0'): id_str = str(client.client_id()) else: - id_str = '%08x' % random.randrange(2**32) - key = '__REDIS-PY-%s__' % id_str + id_str = f'{random.randrange(2 ** 32):08x}' + key = f'__REDIS-PY-{id_str}__' client.get(key) while True: monitor_response = monitor.next_command() diff --git a/tests/test_cluster.py b/tests/test_cluster.py index ac223b759d..d12e47ed02 100644 --- a/tests/test_cluster.py +++ b/tests/test_cluster.py @@ -333,8 +333,7 @@ def ok_response(connection, *args, **options): return "MOCK_OK" parse_response.side_effect = ok_response - raise AskError("12182 {}:{}".format(redirect_node.host, - redirect_node.port)) + raise AskError(f"12182 {redirect_node.host}:{redirect_node.port}") parse_response.side_effect = ask_redirect_effect @@ -2373,8 +2372,7 @@ def test_asking_error(self, r): warnings.warn("skipping this test since the cluster has only one " "node") return - ask_msg = "{} {}:{}".format(r.keyslot(key), ask_node.host, - ask_node.port) + ask_msg = f"{r.keyslot(key)} {ask_node.host}:{ask_node.port}" def raise_ask_error(): raise AskError(ask_msg) @@ -2434,9 +2432,7 @@ def test_moved_redirection_on_slave_with_default(self, r): with r.pipeline() as readwrite_pipe: mock_node_resp(primary, "MOCK_FOO") if replica is not None: - moved_error = "{} {}:{}".format(r.keyslot(key), - primary.host, - primary.port) + moved_error = f"{r.keyslot(key)} {primary.host}:{primary.port}" def raise_moved_error(): raise MovedError(moved_error) diff --git a/tests/test_commands.py b/tests/test_commands.py index f927feeb51..624f4336ed 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1805,11 +1805,11 @@ def test_zadd_incr_with_xx(self, r): def test_zadd_gt_lt(self, r): for i in range(1, 20): - r.zadd('a', {'a%s' % i: i}) + r.zadd('a', {f'a{i}': i}) assert r.zadd('a', {'a20': 5}, gt=3) == 1 for i in range(1, 20): - r.zadd('a', {'a%s' % i: i}) + r.zadd('a', {f'a{i}': i}) assert r.zadd('a', {'a2': 5}, lt=1) == 0 # cannot use both nx and xx options diff --git a/tests/test_connection.py b/tests/test_connection.py index cd8907d85c..0071acab5c 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -15,7 +15,7 @@ def test_invalid_response(r): with mock.patch.object(parser._buffer, 'readline', return_value=raw): with pytest.raises(InvalidResponse) as cm: parser.read_response() - assert str(cm.value) == 'Protocol Error: %r' % raw + assert str(cm.value) == f'Protocol Error: {raw!r}' @skip_if_server_version_lt('4.0.0') diff --git a/tests/test_multiprocessing.py b/tests/test_multiprocessing.py index d0feef155f..5968b2b4fe 100644 --- a/tests/test_multiprocessing.py +++ b/tests/test_multiprocessing.py @@ -89,9 +89,7 @@ def test_pool(self, max_connections, master_host): A child will create its own connections when using a pool created by a parent. """ - pool = ConnectionPool.from_url('redis://{}:{}'.format(master_host[0], - master_host[1], - ), + pool = ConnectionPool.from_url(f'redis://{master_host[0]}:{master_host[1]}', max_connections=max_connections) conn = pool.get_connection('ping') @@ -126,8 +124,7 @@ def test_close_pool_in_main(self, max_connections, master_host): A child process that uses the same pool as its parent isn't affected when the parent disconnects all connections within the pool. """ - pool = ConnectionPool.from_url('redis://{}:{}'.format(master_host[0], - master_host[1]), + pool = ConnectionPool.from_url(f'redis://{master_host[0]}:{master_host[1]}', max_connections=max_connections) conn = pool.get_connection('ping') diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index a759bc944e..a87ed7182d 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -345,7 +345,7 @@ def test_exec_error_in_no_transaction_pipeline_unicode_command(self, r): with pytest.raises(redis.ResponseError) as ex: pipe.execute() - expected = 'Command # 1 (LLEN %s) of pipeline caused error: ' % key + expected = f'Command # 1 (LLEN {key}) of pipeline caused error: ' assert str(ex.value).startswith(expected) assert r[key] == b'1' diff --git a/tests/test_pubsub.py b/tests/test_pubsub.py index 95513a09a8..b019bae6e2 100644 --- a/tests/test_pubsub.py +++ b/tests/test_pubsub.py @@ -55,7 +55,7 @@ def make_subscribe_test_data(pubsub, type): 'unsub_func': pubsub.punsubscribe, 'keys': ['f*', 'b*', 'uni' + chr(4456) + '*'] } - assert False, 'invalid subscribe type: %s' % type + assert False, f'invalid subscribe type: {type}' class TestPubSubSubscribeUnsubscribe: From 0923095fee4ab358034e636a5a5608f252810b97 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 29 Nov 2021 14:58:42 +0200 Subject: [PATCH 3/5] Replace remaining % and .format with f-strings (by hand) --- benchmarks/basic_operations.py | 17 ++--- redis/client.py | 6 +- redis/cluster.py | 96 ++++++++++++++-------------- redis/commands/cluster.py | 7 +- redis/commands/core.py | 33 +++++----- redis/commands/parser.py | 5 +- redis/commands/search/aggregation.py | 9 ++- redis/commands/search/result.py | 2 +- redis/connection.py | 30 +++++---- redis/sentinel.py | 16 ++--- tests/conftest.py | 5 +- tests/test_commands.py | 2 +- 12 files changed, 111 insertions(+), 117 deletions(-) diff --git a/benchmarks/basic_operations.py b/benchmarks/basic_operations.py index 079f975dda..cb009debbd 100644 --- a/benchmarks/basic_operations.py +++ b/benchmarks/basic_operations.py @@ -62,10 +62,9 @@ def set_str(conn, num, pipeline_size, data_size): if pipeline_size > 1: conn = conn.pipeline() - format_str = '{:0<%d}' % data_size - set_data = format_str.format('a') + set_data = 'a'.ljust(data_size, '0') for i in range(num): - conn.set('set_str:%d' % i, set_data) + conn.set(f'set_str:{i}', set_data) if pipeline_size > 1 and i % pipeline_size == 0: conn.execute() @@ -78,10 +77,9 @@ def set_int(conn, num, pipeline_size, data_size): if pipeline_size > 1: conn = conn.pipeline() - format_str = '{:0<%d}' % data_size - set_data = int(format_str.format('1')) + set_data = 10 ** (data_size - 1) for i in range(num): - conn.set('set_int:%d' % i, set_data) + conn.set(f'set_int:{i}', set_data) if pipeline_size > 1 and i % pipeline_size == 0: conn.execute() @@ -95,7 +93,7 @@ def get_str(conn, num, pipeline_size, data_size): conn = conn.pipeline() for i in range(num): - conn.get('set_str:%d' % i) + conn.get(f'set_str:{i}') if pipeline_size > 1 and i % pipeline_size == 0: conn.execute() @@ -109,7 +107,7 @@ def get_int(conn, num, pipeline_size, data_size): conn = conn.pipeline() for i in range(num): - conn.get('set_int:%d' % i) + conn.get(f'set_int:{i}') if pipeline_size > 1 and i % pipeline_size == 0: conn.execute() @@ -136,8 +134,7 @@ def lpush(conn, num, pipeline_size, data_size): if pipeline_size > 1: conn = conn.pipeline() - format_str = '{:0<%d}' % data_size - set_data = int(format_str.format('1')) + set_data = 10 ** (data_size - 1) for i in range(num): conn.lpush('lpush_key', set_data) if pipeline_size > 1 and i % pipeline_size == 0: diff --git a/redis/client.py b/redis/client.py index 2e4c18ba08..9f2907ee52 100755 --- a/redis/client.py +++ b/redis/client.py @@ -1805,8 +1805,10 @@ def raise_first_error(self, commands, response): def annotate_exception(self, exception, number, command): cmd = ' '.join(map(safe_str, command)) - msg = 'Command # %d (%s) of pipeline caused error: %s' % ( - number, cmd, exception.args[0]) + msg = ( + f'Command # {number} ({cmd}) of pipeline ' + f'caused error: {exception.args[0]}' + ) exception.args = (msg,) + exception.args[1:] def parse_response(self, connection, command_name, **options): diff --git a/redis/cluster.py b/redis/cluster.py index 40a69197ed..c1853aa876 100644 --- a/redis/cluster.py +++ b/redis/cluster.py @@ -740,7 +740,7 @@ def determine_slot(self, *args): raise RedisClusterException( "No way to dispatch this command to Redis Cluster. " "Missing key.\nYou can execute the command by specifying " - "target nodes.\nCommand: {}".format(args) + f"target nodes.\nCommand: {args}" ) if len(keys) > 1: @@ -748,8 +748,9 @@ def determine_slot(self, *args): # the same slot slots = {self.keyslot(key) for key in keys} if len(slots) != 1: - raise RedisClusterException("{} - all keys must map to the " - "same key slot".format(args[0])) + raise RedisClusterException( + f"{args[0]} - all keys must map to the same key slot" + ) return slots.pop() else: # single key command @@ -774,12 +775,12 @@ def _parse_target_nodes(self, target_nodes): # rc.cluster_save_config(rc.get_primaries()) nodes = target_nodes.values() else: - raise TypeError("target_nodes type can be one of the " - "followings: node_flag (PRIMARIES, " - "REPLICAS, RANDOM, ALL_NODES)," - "ClusterNode, list, or " - "dict. The passed type is {0}". - format(type(target_nodes))) + raise TypeError( + "target_nodes type can be one of the following: " + "node_flag (PRIMARIES, REPLICAS, RANDOM, ALL_NODES)," + "ClusterNode, list, or dict. " + f"The passed type is {type(target_nodes)}" + ) return nodes def execute_command(self, *args, **kwargs): @@ -866,9 +867,10 @@ def _execute_command(self, target_node, *args, **kwargs): command in READ_COMMANDS) moved = False - log.debug("Executing command {0} on target node: {1} {2}". - format(command, target_node.server_type, - target_node.name)) + log.debug( + f"Executing command {command} on target node: " + f"{target_node.server_type} {target_node.name}" + ) redis_node = self.get_redis_connection(target_node) connection = get_connection(redis_node, *args, **kwargs) if asking: @@ -1005,13 +1007,13 @@ def __init__(self, host, port, server_type=None, redis_connection=None): self.redis_connection = redis_connection def __repr__(self): - return '[host={},port={},' \ - 'name={},server_type={},redis_connection={}]' \ - .format(self.host, - self.port, - self.name, - self.server_type, - self.redis_connection) + return ( + f'[host={self.host},' + f'port={self.port},' + f'name={self.name},' + f'server_type={self.server_type},' + f'redis_connection={self.redis_connection}]' + ) def __eq__(self, obj): return isinstance(obj, ClusterNode) and obj.name == self.name @@ -1133,9 +1135,8 @@ def get_node_from_slot(self, slot, read_from_replicas=False, if self.slots_cache.get(slot) is None or \ len(self.slots_cache[slot]) == 0: raise SlotNotCoveredError( - 'Slot "{}" not covered by the cluster. ' - '"require_full_coverage={}"'.format( - slot, self._require_full_coverage) + f'Slot "{slot}" not covered by the cluster. ' + f'"require_full_coverage={self._require_full_coverage}"' ) if read_from_replicas is True: @@ -1194,7 +1195,7 @@ def node_require_full_coverage(node): except Exception as e: raise RedisClusterException( 'ERROR sending "config get cluster-require-full-coverage"' - ' command to redis server: {}, {}'.format(node.name, e) + f' command to redis server: {node.name}, {e}' ) # at least one node should have cluster-require-full-coverage yes @@ -1267,7 +1268,7 @@ def initialize(self): msg = e.__str__ log.exception('An exception occurred while trying to' ' initialize the cluster using the seed node' - ' {}:\n{}'.format(startup_node.name, msg)) + f' {startup_node.name}:\n{msg}') continue except ResponseError as e: log.exception( @@ -1281,15 +1282,13 @@ def initialize(self): else: raise RedisClusterException( 'ERROR sending "cluster slots" command to redis ' - 'server: {}. error: {}'.format( - startup_node, message) + f'server: {startup_node}. error: {message}' ) except Exception as e: message = e.__str__() raise RedisClusterException( 'ERROR sending "cluster slots" command to redis ' - 'server: {}. error: {}'.format( - startup_node, message) + f'server: {startup_node}. error: {message}' ) # CLUSTER SLOTS command results in the following output: @@ -1340,17 +1339,16 @@ def initialize(self): else: # Validate that 2 nodes want to use the same slot cache # setup - if tmp_slots[i][0].name != target_node.name: + tmp_slot = tmp_slots[i][0] + if tmp_slot.name != target_node.name: disagreements.append( - '{} vs {} on slot: {}'.format( - tmp_slots[i][0].name, target_node.name, i) + f'{tmp_slot.name} vs {target_node.name} on slot: {i}' ) if len(disagreements) > 5: raise RedisClusterException( - 'startup_nodes could not agree on a valid' - ' slots cache: {}'.format( - ", ".join(disagreements)) + f'startup_nodes could not agree on a valid ' + f'slots cache: {", ".join(disagreements)}' ) if not startup_nodes_reachable: @@ -1368,9 +1366,8 @@ def initialize(self): # Despite the requirement that the slots be covered, there # isn't a full coverage raise RedisClusterException( - 'All slots are not covered after query all startup_nodes.' - ' {} of {} covered...'.format( - len(self.slots_cache), REDIS_CLUSTER_HASH_SLOTS) + f'All slots are not covered after query all startup_nodes. ' + f'{len(self.slots_cache)} of {REDIS_CLUSTER_HASH_SLOTS} covered...' ) elif not fully_covered and not self._require_full_coverage: # The user set require_full_coverage to False. @@ -1387,8 +1384,7 @@ def initialize(self): 'cluster-require-full-coverage configuration to no on ' 'all of the cluster nodes if you wish the cluster to ' 'be able to serve without being fully covered.' - ' {} of {} covered...'.format( - len(self.slots_cache), REDIS_CLUSTER_HASH_SLOTS) + f'{len(self.slots_cache)} of {REDIS_CLUSTER_HASH_SLOTS} covered...' ) # Set the tmp variables to the real variables @@ -1642,8 +1638,10 @@ def annotate_exception(self, exception, number, command): Provides extra context to the exception prior to it being handled """ cmd = ' '.join(map(safe_str, command)) - msg = 'Command # %d (%s) of pipeline caused error: %s' % ( - number, cmd, exception.args[0]) + msg = ( + f'Command # {number} ({cmd}) of pipeline ' + f'caused error: {exception.args[0]}' + ) exception.args = (msg,) + exception.args[1:] def execute(self, raise_on_error=True): @@ -1832,12 +1830,12 @@ def _send_cluster_commands(self, stack, # If a lot of commands have failed, we'll be setting the # flag to rebuild the slots table from scratch. # So MOVED errors should correct themselves fairly quickly. - msg = 'An exception occurred during pipeline execution. ' \ - 'args: {0}, error: {1} {2}'.\ - format(attempt[-1].args, - type(attempt[-1].result).__name__, - str(attempt[-1].result)) - log.exception(msg) + log.exception( + f'An exception occurred during pipeline execution. ' + f'args: {attempt[-1].args}, ' + f'error: {type(attempt[-1].result).__name__} ' + f'{str(attempt[-1].result)}' + ) self.reinitialize_counter += 1 if self._should_reinitialized(): self.nodes_manager.initialize() @@ -1929,8 +1927,8 @@ def block_pipeline_command(func): def inner(*args, **kwargs): raise RedisClusterException( - "ERROR: Calling pipelined function {} is blocked when " - "running redis in cluster mode...".format(func.__name__)) + f"ERROR: Calling pipelined function {func.__name__} is blocked when " + f"running redis in cluster mode...") return inner diff --git a/redis/commands/cluster.py b/redis/commands/cluster.py index be77207a96..e6b0a08924 100644 --- a/redis/commands/cluster.py +++ b/redis/commands/cluster.py @@ -638,11 +638,10 @@ def stralgo(self, algo, value1, value2, specific_argument='strings', # check validity supported_algo = ['LCS'] if algo not in supported_algo: - raise DataError("The supported algorithms are: %s" - % (', '.join(supported_algo))) + supported_algos_str = ', '.join(supported_algo) + raise DataError(f"The supported algorithms are: {supported_algos_str}") if specific_argument not in ['keys', 'strings']: - raise DataError("specific_argument can be only" - " keys or strings") + raise DataError("specific_argument can be only keys or strings") if len and idx: raise DataError("len and idx cannot be provided together.") diff --git a/redis/commands/core.py b/redis/commands/core.py index 08210b23df..0285f80e0f 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -227,8 +227,8 @@ def acl_setuser(self, username, enabled=False, nopass=False, elif password.startswith(b'-'): pieces.append(b'<%s' % password[1:]) else: - raise DataError('Password %d must be prefixeed with a ' - '"+" to add or a "-" to remove' % i) + raise DataError(f'Password {i} must be prefixed with a ' + f'"+" to add or a "-" to remove') if hashed_passwords: # as most users will have only one password, allow remove_passwords @@ -241,8 +241,8 @@ def acl_setuser(self, username, enabled=False, nopass=False, elif hashed_password.startswith(b'-'): pieces.append(b'!%s' % hashed_password[1:]) else: - raise DataError('Hashed %d password must be prefixeed ' - 'with a "+" to add or a "-" to remove' % i) + raise DataError(f'Hashed password {i} must be prefixed with a ' + f'"+" to add or a "-" to remove') if nopass: pieces.append(b'nopass') @@ -260,16 +260,18 @@ def acl_setuser(self, username, enabled=False, nopass=False, elif category.startswith(b'-'): pieces.append(b'-@%s' % category[1:]) else: - raise DataError('Category "%s" must be prefixed with ' - '"+" or "-"' - % encoder.decode(category, force=True)) + raise DataError( + f'Category "{encoder.decode(category, force=True)}" ' + 'must be prefixed with "+" or "-"' + ) if commands: for cmd in commands: cmd = encoder.encode(cmd) if not cmd.startswith(b'+') and not cmd.startswith(b'-'): - raise DataError('Command "%s" must be prefixed with ' - '"+" or "-"' - % encoder.decode(cmd, force=True)) + raise DataError( + f'Command "{encoder.decode(cmd, force=True)}" ' + 'must be prefixed with "+" or "-"' + ) pieces.append(cmd) if keys: @@ -1552,11 +1554,10 @@ def stralgo(self, algo, value1, value2, specific_argument='strings', # check validity supported_algo = ['LCS'] if algo not in supported_algo: - raise DataError("The supported algorithms are: %s" - % (', '.join(supported_algo))) + supported_algos_str = ', '.join(supported_algo) + raise DataError(f"The supported algorithms are: {supported_algos_str}") if specific_argument not in ['keys', 'strings']: - raise DataError("specific_argument can be only" - " keys or strings") + raise DataError("specific_argument can be only keys or strings") if len and idx: raise DataError("len and idx cannot be provided together.") @@ -3464,8 +3465,8 @@ def hmset(self, name, mapping): For more information check https://redis.io/commands/hmset """ warnings.warn( - '%s.hmset() is deprecated. Use %s.hset() instead.' - % (self.__class__.__name__, self.__class__.__name__), + f'{self.__class__.__name__}.hmset() is deprecated. ' + f'Use {self.__class__.__name__}.hset() instead.', DeprecationWarning, stacklevel=2, ) diff --git a/redis/commands/parser.py b/redis/commands/parser.py index 9e313cc1f7..26b190c674 100644 --- a/redis/commands/parser.py +++ b/redis/commands/parser.py @@ -46,8 +46,9 @@ def get_keys(self, redis_conn, *args): # version has changed, the commands may not be current self.initialize(redis_conn) if cmd_name not in self.commands: - raise RedisError("{} command doesn't exist in Redis " - "commands".format(cmd_name.upper())) + raise RedisError( + f"{cmd_name.upper()} command doesn't exist in Redis commands" + ) command = self.commands.get(cmd_name) if 'movablekeys' in command['flags']: diff --git a/redis/commands/search/aggregation.py b/redis/commands/search/aggregation.py index 9e8e00aeff..b1ac6b04dc 100644 --- a/redis/commands/search/aggregation.py +++ b/redis/commands/search/aggregation.py @@ -392,9 +392,8 @@ def __init__(self, rows, cursor, schema): self.schema = schema def __repr__(self): - return "<{} at 0x{:x} Rows={}, Cursor={}>".format( - self.__class__.__name__, - id(self), - len(self.rows), - self.cursor.cid if self.cursor else -1, + cid = self.cursor.cid if self.cursor else -1 + return ( + f"<{self.__class__.__name__} at 0x{id(self):x} " + f"Rows={len(self.rows)}, Cursor={cid}>" ) diff --git a/redis/commands/search/result.py b/redis/commands/search/result.py index a799395777..57ba53d5ca 100644 --- a/redis/commands/search/result.py +++ b/redis/commands/search/result.py @@ -70,4 +70,4 @@ def __init__( self.docs.append(doc) def __repr__(self): - return "Result{%d total, docs: %s}" % (self.total, self.docs) + return f"Result{{{self.total} total, docs: {self.docs}}}" diff --git a/redis/connection.py b/redis/connection.py index 07486a9289..ef3a667c16 100755 --- a/redis/connection.py +++ b/redis/connection.py @@ -107,8 +107,8 @@ def encode(self, value): elif not isinstance(value, str): # a value we don't know how to deal with. throw an error typename = type(value).__name__ - raise DataError("Invalid input of type: '%s'. Convert to a " - "bytes, string, int or float first." % typename) + raise DataError(f"Invalid input of type: '{typename}'. " + f"Convert to a bytes, string, int or float first.") if isinstance(value, str): value = value.encode(self.encoding, self.encoding_errors) return value @@ -646,8 +646,10 @@ def _error_message(self, exception): if len(exception.args) == 1: return f"Error connecting to {self.host}:{self.port}. {exception.args[0]}." else: - return "Error %s connecting to %s:%s. %s." % \ - (exception.args[0], self.host, self.port, exception.args[1]) + return ( + f"Error {exception.args[0]} connecting to " + f"{self.host}:{self.port}. {exception.args[1]}." + ) def on_connect(self): "Initialize the connection, authenticate and select a database" @@ -766,8 +768,9 @@ def read_response(self, disable_decoding=False): raise TimeoutError(f"Timeout reading from {self.host}:{self.port}") except OSError as e: self.disconnect() - raise ConnectionError("Error while reading from %s:%s : %s" % - (self.host, self.port, e.args)) + raise ConnectionError( + f"Error while reading from {self.host}:{self.port}" + f" : {e.args}") except BaseException: self.disconnect() raise @@ -943,8 +946,10 @@ def _error_message(self, exception): if len(exception.args) == 1: return f"Error connecting to unix socket: {self.path}. {exception.args[0]}." else: - return "Error %s connecting to unix socket: %s. %s." % \ - (exception.args[0], self.path, exception.args[1]) + return ( + f"Error {exception.args[0]} connecting to unix socket: " + f"{self.path}. {exception.args[1]}." + ) FALSE_STRINGS = ('0', 'F', 'FALSE', 'N', 'NO') @@ -1016,9 +1021,8 @@ def parse_url(url): if url.scheme == 'rediss': kwargs['connection_class'] = SSLConnection else: - valid_schemes = 'redis://, rediss://, unix://' raise ValueError('Redis URL must specify one of the following ' - 'schemes (%s)' % valid_schemes) + 'schemes (redis://, rediss://, unix://)') return kwargs @@ -1102,9 +1106,9 @@ def __init__(self, connection_class=Connection, max_connections=None, self.reset() def __repr__(self): - return "{}<{}>".format( - type(self).__name__, - repr(self.connection_class(**self.connection_kwargs)), + return ( + f"{type(self).__name__}" + f"<{repr(self.connection_class(**self.connection_kwargs))}>" ) def reset(self): diff --git a/redis/sentinel.py b/redis/sentinel.py index e4caa0fe7c..06877bd167 100644 --- a/redis/sentinel.py +++ b/redis/sentinel.py @@ -91,11 +91,8 @@ def __init__(self, service_name, sentinel_manager, **kwargs): self.sentinel_manager = sentinel_manager def __repr__(self): - return "{}'.format( - type(self).__name__, - ','.join(sentinel_addresses)) + return f'{type(self).__name__}' def check_master_state(self, state, service_name): if not state['is_master'] or state['is_sdown'] or state['is_odown']: diff --git a/tests/conftest.py b/tests/conftest.py index e401575f6c..8ed39abddc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -101,9 +101,8 @@ def wait_for_cluster_creation(redis_url, cluster_nodes, timeout=20): if now >= end_time: available_nodes = 0 if client is None else len(client.get_nodes()) raise RedisClusterException( - "The cluster did not become available after {} seconds. " - "Only {} nodes out of {} are available".format( - timeout, available_nodes, cluster_nodes)) + f"The cluster did not become available after {timeout} seconds. " + f"Only {available_nodes} nodes out of {cluster_nodes} are available") def skip_if_server_version_lt(min_version): diff --git a/tests/test_commands.py b/tests/test_commands.py index 624f4336ed..444a163489 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -99,7 +99,7 @@ def teardown(): assert r.acl_deluser(username) == 1 # now, a group of users - users = ['bogususer_%d' % r for r in range(0, 5)] + users = [f'bogususer_{r}' for r in range(0, 5)] for u in users: r.acl_setuser(u, enabled=False, reset=True) assert r.acl_deluser(*users) > 1 From d965722c7af4130e2bbfe6447b9a8ed01378504d Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 29 Nov 2021 15:29:26 +0200 Subject: [PATCH 4/5] Adjust flake8 max-line-length to 88 in anticipation of redis/redis-py#1644 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index dd68274f2d..409fdbd9d9 100644 --- a/tox.ini +++ b/tox.ini @@ -130,7 +130,7 @@ commands = /usr/bin/echo deps_files = dev_requirements.txt docker = commands = - flake8 + flake8 --max-line-length=88 vulture redis whitelist.py --min-confidence 80 skipsdist = true skip_install = true From 428afe3c562f763203fe88024f037bae4e3509ae Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 29 Nov 2021 19:40:57 +0200 Subject: [PATCH 5/5] Add flynt to lint (to enforce f-string use) --- dev_requirements.txt | 1 + tox.ini | 1 + 2 files changed, 2 insertions(+) diff --git a/dev_requirements.txt b/dev_requirements.txt index 7f099cb541..56ac08efe2 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,4 +1,5 @@ flake8>=3.9.2 +flynt~=0.69.0 pytest==6.2.5 pytest-timeout==2.0.1 tox==3.24.4 diff --git a/tox.ini b/tox.ini index 409fdbd9d9..d06f7e3d1e 100644 --- a/tox.ini +++ b/tox.ini @@ -132,6 +132,7 @@ docker = commands = flake8 --max-line-length=88 vulture redis whitelist.py --min-confidence 80 + flynt --fail-on-change --dry-run . skipsdist = true skip_install = true