From 4eea92d6109d64ae6b68ef7c4d0907ab50e999fa Mon Sep 17 00:00:00 2001 From: Alp Aribal Date: Sat, 7 Dec 2019 22:27:30 +0100 Subject: [PATCH 1/2] CLN: change str.format() to f-string --- pandas/core/arrays/string_.py | 12 +++--- pandas/core/arrays/timedeltas.py | 55 +++++++------------------- pandas/core/common.py | 2 +- pandas/core/computation/engines.py | 3 +- pandas/core/computation/expr.py | 31 ++++++--------- pandas/core/computation/expressions.py | 2 +- pandas/core/computation/ops.py | 14 +++---- pandas/core/computation/pytables.py | 43 ++++++++------------ pandas/core/computation/scope.py | 10 ++--- 9 files changed, 63 insertions(+), 109 deletions(-) diff --git a/pandas/core/arrays/string_.py b/pandas/core/arrays/string_.py index f6af05ab4d9e7..2de19a3319cc5 100644 --- a/pandas/core/arrays/string_.py +++ b/pandas/core/arrays/string_.py @@ -171,7 +171,7 @@ def _validate(self): if self._ndarray.dtype != "object": raise ValueError( "StringArray requires a sequence of strings. Got " - "'{}' dtype instead.".format(self._ndarray.dtype) + f"'{self._ndarray.dtype}' dtype instead." ) @classmethod @@ -222,7 +222,7 @@ def __setitem__(self, key, value): value = StringDtype.na_value elif not isinstance(value, str): raise ValueError( - "Cannot set non-string value '{}' into a StringArray.".format(value) + f"Cannot set non-string value '{value}' into a StringArray." ) else: if not is_array_like(value): @@ -245,7 +245,7 @@ def astype(self, dtype, copy=True): return super().astype(dtype, copy) def _reduce(self, name, skipna=True, **kwargs): - raise TypeError("Cannot perform reduction '{}' with string dtype".format(name)) + raise TypeError(f"Cannot perform reduction '{name}' with string dtype") def value_counts(self, dropna=False): from pandas import value_counts @@ -269,9 +269,7 @@ def method(self, other): if len(other) != len(self): # prevent improper broadcasting when other is 2D raise ValueError( - "Lengths of operands do not match: {} != {}".format( - len(self), len(other) - ) + f"Lengths of operands do not match: {len(self)} != {len(other)}" ) other = np.asarray(other) @@ -287,7 +285,7 @@ def method(self, other): dtype = "object" if mask.any() else "bool" return np.asarray(result, dtype=dtype) - return compat.set_function_name(method, "__{}__".format(op.__name__), cls) + return compat.set_function_name(method, f"__{op.__name__}__", cls) @classmethod def _add_arithmetic_ops(cls): diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 892d1bc281ca9..56c4a1a201eeb 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -70,7 +70,7 @@ def f(self): return result f.__name__ = name - f.__doc__ = "\n{}\n".format(docstring) + f.__doc__ = f"\n{docstring}\n" return property(f) @@ -78,7 +78,7 @@ def _td_array_cmp(cls, op): """ Wrap comparison operations to convert timedelta-like to timedelta64 """ - opname = "__{name}__".format(name=op.__name__) + opname = f"__{op.__name__}__" nat_result = opname == "__ne__" @unpack_zerodim_and_defer(opname) @@ -215,10 +215,10 @@ def __init__(self, values, dtype=_TD_DTYPE, freq=None, copy=False): if not isinstance(values, np.ndarray): msg = ( - "Unexpected type '{}'. 'values' must be a TimedeltaArray " - "ndarray, or Series or Index containing one of those." + f"Unexpected type '{type(values).__name__}'. 'values' must be a" + " TimedeltaArray ndarray, or Series or Index containing one of those." ) - raise ValueError(msg.format(type(values).__name__)) + raise ValueError(msg) if values.ndim != 1: raise ValueError("Only 1-dimensional input arrays are supported.") @@ -351,10 +351,7 @@ def _validate_fill_value(self, fill_value): elif isinstance(fill_value, (timedelta, np.timedelta64, Tick)): fill_value = Timedelta(fill_value).value else: - raise ValueError( - "'fill_value' should be a Timedelta. " - "Got '{got}'.".format(got=fill_value) - ) + raise ValueError(f"'fill_value' should be a Timedelta. Got '{fill_value}'.") return fill_value def astype(self, dtype, copy=True): @@ -461,9 +458,7 @@ def _format_native_types(self, na_rep="NaT", date_format=None): def _add_offset(self, other): assert not isinstance(other, Tick) raise TypeError( - "cannot add the type {typ} to a {cls}".format( - typ=type(other).__name__, cls=type(self).__name__ - ) + f"cannot add the type {type(other).__name__} to a {type(self).__name__}" ) def _add_delta(self, delta): @@ -523,9 +518,7 @@ def _addsub_offset_array(self, other, op): return super()._addsub_offset_array(other, op) except AttributeError: raise TypeError( - "Cannot add/subtract non-tick DateOffset to {cls}".format( - cls=type(self).__name__ - ) + f"Cannot add/subtract non-tick DateOffset to {type(self).__name__}" ) def __mul__(self, other): @@ -634,9 +627,7 @@ def __rtruediv__(self, other): elif lib.is_scalar(other): raise TypeError( - "Cannot divide {typ} by {cls}".format( - typ=type(other).__name__, cls=type(self).__name__ - ) + f"Cannot divide {type(other).__name__} by {type(self).__name__}" ) if not hasattr(other, "dtype"): @@ -659,9 +650,7 @@ def __rtruediv__(self, other): else: raise TypeError( - "Cannot divide {dtype} data by {cls}".format( - dtype=other.dtype, cls=type(self).__name__ - ) + f"Cannot divide {other.dtype} data by {type(self).__name__}" ) def __floordiv__(self, other): @@ -724,11 +713,7 @@ def __floordiv__(self, other): else: dtype = getattr(other, "dtype", type(other).__name__) - raise TypeError( - "Cannot divide {typ} by {cls}".format( - typ=dtype, cls=type(self).__name__ - ) - ) + raise TypeError(f"Cannot divide {dtype} by {type(self).__name__}") def __rfloordiv__(self, other): if isinstance(other, (ABCSeries, ABCDataFrame, ABCIndexClass)): @@ -749,9 +734,7 @@ def __rfloordiv__(self, other): return result raise TypeError( - "Cannot divide {typ} by {cls}".format( - typ=type(other).__name__, cls=type(self).__name__ - ) + f"Cannot divide {type(other).__name__} by {type(self).__name__}" ) if not hasattr(other, "dtype"): @@ -779,11 +762,7 @@ def __rfloordiv__(self, other): else: dtype = getattr(other, "dtype", type(other).__name__) - raise TypeError( - "Cannot divide {typ} by {cls}".format( - typ=dtype, cls=type(self).__name__ - ) - ) + raise TypeError(f"Cannot divide {dtype} by {type(self).__name__}") def __mod__(self, other): # Note: This is a naive implementation, can likely be optimized @@ -1056,11 +1035,7 @@ def sequence_to_td64ns(data, copy=False, unit="ns", errors="raise"): else: # This includes datetime64-dtype, see GH#23539, GH#29794 - raise TypeError( - "dtype {dtype} cannot be converted to timedelta64[ns]".format( - dtype=data.dtype - ) - ) + raise TypeError(f"dtype {data.dtype} cannot be converted to timedelta64[ns]") data = np.array(data, copy=copy) if data.ndim != 1: @@ -1096,7 +1071,7 @@ def ints_to_td64ns(data, unit="ns"): copy_made = True if unit != "ns": - dtype_str = "timedelta64[{unit}]".format(unit=unit) + dtype_str = f"timedelta64[{unit}]" data = data.view(dtype_str) # TODO: watch out for overflows when converting from lower-resolution diff --git a/pandas/core/common.py b/pandas/core/common.py index d62f1557952a8..9017584171850 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -388,7 +388,7 @@ def standardize_mapping(into): return partial(collections.defaultdict, into.default_factory) into = type(into) if not issubclass(into, abc.Mapping): - raise TypeError("unsupported type: {into}".format(into=into)) + raise TypeError(f"unsupported type: {into}") elif into == collections.defaultdict: raise TypeError("to_dict() only accepts initialized defaultdicts") return into diff --git a/pandas/core/computation/engines.py b/pandas/core/computation/engines.py index a4eaa897ca01e..dbfd6c04eee32 100644 --- a/pandas/core/computation/engines.py +++ b/pandas/core/computation/engines.py @@ -31,8 +31,7 @@ def _check_ne_builtin_clash(expr): if overlap: s = ", ".join(repr(x) for x in overlap) raise NumExprClobberingError( - 'Variables in expression "{expr}" ' - "overlap with builtins: ({s})".format(expr=expr, s=s) + f'Variables in expression "{expr}" overlap with builtins: ({s})' ) diff --git a/pandas/core/computation/expr.py b/pandas/core/computation/expr.py index 9330586bbce68..9b422b28c3c27 100644 --- a/pandas/core/computation/expr.py +++ b/pandas/core/computation/expr.py @@ -282,10 +282,9 @@ def _filter_nodes(superclass, all_nodes=_all_nodes): # and we don't want `stmt` and friends in their so get only the class whose # names are capitalized _base_supported_nodes = (_all_node_names - _unsupported_nodes) | _hacked_nodes -_msg = "cannot both support and not support {intersection}".format( - intersection=_unsupported_nodes & _base_supported_nodes -) -assert not _unsupported_nodes & _base_supported_nodes, _msg +intersection = _unsupported_nodes & _base_supported_nodes +_msg = f"cannot both support and not support {intersection}" +assert not intersection, _msg def _node_not_implemented(node_name, cls): @@ -312,7 +311,7 @@ def disallowed(cls): cls.unsupported_nodes = () for node in nodes: new_method = _node_not_implemented(node, cls) - name = "visit_{node}".format(node=node) + name = f"visit_{node}" cls.unsupported_nodes += (name,) setattr(cls, name, new_method) return cls @@ -349,13 +348,13 @@ def add_ops(op_classes): def f(cls): for op_attr_name, op_class in op_classes.items(): - ops = getattr(cls, "{name}_ops".format(name=op_attr_name)) - ops_map = getattr(cls, "{name}_op_nodes_map".format(name=op_attr_name)) + ops = getattr(cls, f"{op_attr_name}_ops") + ops_map = getattr(cls, f"{op_attr_name}_op_nodes_map") for op in ops: op_node = ops_map[op] if op_node is not None: made_op = _op_maker(op_class, op) - setattr(cls, "visit_{node}".format(node=op_node), made_op) + setattr(cls, f"visit_{op_node}", made_op) return cls return f @@ -529,8 +528,8 @@ def _maybe_evaluate_binop( if res.has_invalid_return_type: raise TypeError( - "unsupported operand type(s) for {op}:" - " '{lhs}' and '{rhs}'".format(op=res.op, lhs=lhs.type, rhs=rhs.type) + f"unsupported operand type(s) for {res.op}:" + f" '{lhs.type}' and '{rhs.type}'" ) if self.engine != "pytables": @@ -677,7 +676,7 @@ def visit_Attribute(self, node, **kwargs): if isinstance(value, ast.Name) and value.id == attr: return resolved - raise ValueError("Invalid Attribute context {name}".format(name=ctx.__name__)) + raise ValueError(f"Invalid Attribute context {ctx.__name__}") def visit_Call(self, node, side=None, **kwargs): @@ -697,7 +696,7 @@ def visit_Call(self, node, side=None, **kwargs): raise if res is None: - raise ValueError("Invalid function call {func}".format(func=node.func.id)) + raise ValueError(f"Invalid function call {node.func.id}") if hasattr(res, "value"): res = res.value @@ -707,8 +706,7 @@ def visit_Call(self, node, side=None, **kwargs): if node.keywords: raise TypeError( - 'Function "{name}" does not support keyword ' - "arguments".format(name=res.name) + f'Function "{res.name}" does not support keyword arguments' ) return res(*new_args, **kwargs) @@ -719,10 +717,7 @@ def visit_Call(self, node, side=None, **kwargs): for key in node.keywords: if not isinstance(key, ast.keyword): - raise ValueError( - "keyword error in function call " - "'{func}'".format(func=node.func.id) - ) + raise ValueError(f"keyword error in function call '{node.func.id}'") if key.arg: kwargs[key.arg] = self.visit(key.value).value diff --git a/pandas/core/computation/expressions.py b/pandas/core/computation/expressions.py index 1a493bc58a227..7e959889ee997 100644 --- a/pandas/core/computation/expressions.py +++ b/pandas/core/computation/expressions.py @@ -109,7 +109,7 @@ def _evaluate_numexpr(op, op_str, a, b): b_value = getattr(b, "values", b) result = ne.evaluate( - "a_value {op} b_value".format(op=op_str), + f"a_value {op_str} b_value", local_dict={"a_value": a_value, "b_value": b_value}, casting="safe", ) diff --git a/pandas/core/computation/ops.py b/pandas/core/computation/ops.py index fe02963e4782d..2215629ec0717 100644 --- a/pandas/core/computation/ops.py +++ b/pandas/core/computation/ops.py @@ -212,8 +212,8 @@ def __repr__(self) -> str: Print a generic n-ary operator and its operands using infix notation. """ # recurse over the operands - parened = ("({0})".format(pprint_thing(opr)) for opr in self.operands) - return pprint_thing(" {0} ".format(self.op).join(parened)) + parened = (f"({pprint_thing(opr)})" for opr in self.operands) + return pprint_thing(f" {self.op} ".join(parened)) @property def return_type(self): @@ -506,8 +506,8 @@ def __init__(self, lhs, rhs, **kwargs): if not isnumeric(lhs.return_type) or not isnumeric(rhs.return_type): raise TypeError( - "unsupported operand type(s) for {0}:" - " '{1}' and '{2}'".format(self.op, lhs.return_type, rhs.return_type) + f"unsupported operand type(s) for {self.op}:" + f" '{lhs.return_type}' and '{rhs.return_type}'" ) # do not upcast float32s to float64 un-necessarily @@ -554,7 +554,7 @@ def __call__(self, env): return self.func(operand) def __repr__(self) -> str: - return pprint_thing("{0}({1})".format(self.op, self.operand)) + return pprint_thing(f"{self.op}({self.operand})") @property def return_type(self) -> np.dtype: @@ -580,7 +580,7 @@ def __call__(self, env): def __repr__(self) -> str: operands = map(str, self.operands) - return pprint_thing("{0}({1})".format(self.op, ",".join(operands))) + return pprint_thing(f"{self.op}({','.join(operands)})") class FuncNode: @@ -592,7 +592,7 @@ def __init__(self, name: str): and _NUMEXPR_VERSION < LooseVersion("2.6.9") and name in ("floor", "ceil") ): - raise ValueError('"{0}" is not a supported function'.format(name)) + raise ValueError(f'"{name}" is not a supported function') self.name = name self.func = getattr(np, name) diff --git a/pandas/core/computation/pytables.py b/pandas/core/computation/pytables.py index 8eef37a359a8e..bd65992f0a536 100644 --- a/pandas/core/computation/pytables.py +++ b/pandas/core/computation/pytables.py @@ -172,7 +172,7 @@ def metadata(self): def generate(self, v) -> str: """ create and return the op string for this TermValue """ val = v.tostring(self.encoding) - return "({lhs} {op} {val})".format(lhs=self.lhs, op=self.op, val=val) + return f"({self.lhs} {self.op} {val})" def convert_value(self, v) -> "TermValue": """ convert the expression that is in the term to something that is @@ -233,11 +233,7 @@ def stringify(value): # string quoting return TermValue(v, stringify(v), "string") else: - raise TypeError( - "Cannot compare {v} of type {typ} to {kind} column".format( - v=v, typ=type(v), kind=kind - ) - ) + raise TypeError(f"Cannot compare {v} of type {type(v)} to {kind} column") def convert_values(self): pass @@ -249,9 +245,7 @@ class FilterBinOp(BinOp): def __repr__(self) -> str: if self.filter is None: return "Filter: Not Initialized" - return pprint_thing( - "[Filter : [{lhs}] -> [{op}]".format(lhs=self.filter[0], op=self.filter[1]) - ) + return pprint_thing(f"[Filter : [{self.filter[0]}] -> [{self.filter[1]}]") def invert(self): """ invert the filter """ @@ -268,7 +262,7 @@ def format(self): def evaluate(self): if not self.is_valid: - raise ValueError("query term is not valid [{slf}]".format(slf=self)) + raise ValueError(f"query term is not valid [{self}]") rhs = self.conform(self.rhs) values = list(rhs) @@ -292,8 +286,7 @@ def evaluate(self): else: raise TypeError( - "passing a filterable condition to a non-table " - "indexer [{slf}]".format(slf=self) + f"passing a filterable condition to a non-table indexer [{self}]" ) return self @@ -315,7 +308,7 @@ def evaluate(self): class ConditionBinOp(BinOp): def __repr__(self) -> str: - return pprint_thing("[Condition : [{cond}]]".format(cond=self.condition)) + return pprint_thing(f"[Condition : [{self.condition}]]") def invert(self): """ invert the condition """ @@ -333,7 +326,7 @@ def format(self): def evaluate(self): if not self.is_valid: - raise ValueError("query term is not valid [{slf}]".format(slf=self)) + raise ValueError(f"query term is not valid [{self}]") # convert values if we are in the table if not self.is_in_table: @@ -348,7 +341,7 @@ def evaluate(self): # too many values to create the expression? if len(values) <= self._max_selectors: vs = [self.generate(v) for v in values] - self.condition = "({cond})".format(cond=" | ".join(vs)) + self.condition = f"({' | '.join(vs)})" # use a filter after reading else: @@ -361,9 +354,7 @@ def evaluate(self): class JointConditionBinOp(ConditionBinOp): def evaluate(self): - self.condition = "({lhs} {op} {rhs})".format( - lhs=self.lhs.condition, op=self.op, rhs=self.rhs.condition - ) + self.condition = f"({self.lhs.condition} {self.op} {self.rhs.condition})" return self @@ -397,7 +388,7 @@ def __init__(self, env, engine, parser, **kwargs): bin_node = self.binary_op_nodes_map[bin_op] setattr( self, - "visit_{node}".format(node=bin_node), + f"visit_{bin_node}", lambda node, bin_op=bin_op: partial(BinOp, bin_op, **kwargs), ) @@ -456,7 +447,7 @@ def visit_Attribute(self, node, **kwargs): if isinstance(value, ast.Name) and value.id == attr: return resolved - raise ValueError("Invalid Attribute context {name}".format(name=ctx.__name__)) + raise ValueError(f"Invalid Attribute context {ctx.__name__}") def translate_In(self, op): return ast.Eq() if isinstance(op, ast.In) else op @@ -556,7 +547,7 @@ def __init__( else: w = _validate_where(w) where[idx] = w - _where = " & ".join(map("({})".format, com.flatten(where))) + _where = " & ".join([f"({w})" for w in com.flatten(where)]) else: _where = where @@ -586,15 +577,15 @@ def evaluate(self): self.condition = self.terms.prune(ConditionBinOp) except AttributeError: raise ValueError( - "cannot process expression [{expr}], [{slf}] " - "is not a valid condition".format(expr=self.expr, slf=self) + f"cannot process expression [{self.expr}], [{self}] " + "is not a valid condition" ) try: self.filter = self.terms.prune(FilterBinOp) except AttributeError: raise ValueError( - "cannot process expression [{expr}], [{slf}] " - "is not a valid filter".format(expr=self.expr, slf=self) + f"cannot process expression [{self.expr}], [{self}] " + "is not a valid filter" ) return self.condition, self.filter @@ -615,7 +606,7 @@ def tostring(self, encoding) -> str: if self.kind == "string": if encoding is not None: return str(self.converted) - return '"{converted}"'.format(converted=self.converted) + return f'"{self.converted}"' elif self.kind == "float": # python 2 str(float) is not always # round-trippable so use repr() diff --git a/pandas/core/computation/scope.py b/pandas/core/computation/scope.py index 78a47afcc0830..70dcf4defdb52 100644 --- a/pandas/core/computation/scope.py +++ b/pandas/core/computation/scope.py @@ -143,10 +143,8 @@ def __init__( def __repr__(self) -> str: scope_keys = _get_pretty_string(list(self.scope.keys())) res_keys = _get_pretty_string(list(self.resolvers.keys())) - unicode_str = "{name}(scope={scope_keys}, resolvers={res_keys})" - return unicode_str.format( - name=type(self).__name__, scope_keys=scope_keys, res_keys=res_keys - ) + unicode_str = f"{type(self).__name__}(scope={scope_keys}, resolvers={res_keys})" + return unicode_str @property def has_resolvers(self) -> bool: @@ -286,9 +284,7 @@ def add_tmp(self, value) -> str: str The name of the temporary variable created. """ - name = "{name}_{num}_{hex_id}".format( - name=type(value).__name__, num=self.ntemps, hex_id=_raw_hex_id(self) - ) + name = f"{type(value).__name__}_{self.ntemps}_{_raw_hex_id(self)}" # add to inner most scope assert name not in self.temps From 6a6f36ad6e21148ab5e7cbf5446be4d8e620e1d6 Mon Sep 17 00:00:00 2001 From: Alp Aribal Date: Sat, 7 Dec 2019 23:41:56 +0100 Subject: [PATCH 2/2] replace list comprehension w/ generator expression --- pandas/core/computation/pytables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/computation/pytables.py b/pandas/core/computation/pytables.py index bd65992f0a536..4d27bcf2845f1 100644 --- a/pandas/core/computation/pytables.py +++ b/pandas/core/computation/pytables.py @@ -547,7 +547,7 @@ def __init__( else: w = _validate_where(w) where[idx] = w - _where = " & ".join([f"({w})" for w in com.flatten(where)]) + _where = " & ".join((f"({w})" for w in com.flatten(where))) else: _where = where