From b82253590a66b4a35ed682bca244f668f16c3e0b Mon Sep 17 00:00:00 2001
From: jschendel <jschendel@users.noreply.github.com>
Date: Thu, 10 Aug 2017 04:26:58 -0600
Subject: [PATCH] CLN: replace %s syntax with .format in core.computation
 (#17209)

---
 pandas/core/computation/align.py       | 11 +++--
 pandas/core/computation/engines.py     |  5 ++-
 pandas/core/computation/eval.py        | 13 +++---
 pandas/core/computation/expr.py        | 45 ++++++++++---------
 pandas/core/computation/expressions.py | 14 +++---
 pandas/core/computation/pytables.py    | 61 ++++++++++++++------------
 pandas/core/computation/scope.py       | 11 +++--
 7 files changed, 87 insertions(+), 73 deletions(-)

diff --git a/pandas/core/computation/align.py b/pandas/core/computation/align.py
index 1c75301082297..691eaebfd5fc1 100644
--- a/pandas/core/computation/align.py
+++ b/pandas/core/computation/align.py
@@ -98,12 +98,11 @@ def _align_core(terms):
 
                 ordm = np.log10(max(1, abs(reindexer_size - term_axis_size)))
                 if ordm >= 1 and reindexer_size >= 10000:
-                    warnings.warn('Alignment difference on axis {0} is larger '
-                                  'than an order of magnitude on term {1!r}, '
-                                  'by more than {2:.4g}; performance may '
-                                  'suffer'.format(axis, terms[i].name, ordm),
-                                  category=PerformanceWarning,
-                                  stacklevel=6)
+                    w = ('Alignment difference on axis {axis} is larger '
+                         'than an order of magnitude on term {term!r}, by '
+                         'more than {ordm:.4g}; performance may suffer'
+                         ).format(axis=axis, term=terms[i].name, ordm=ordm)
+                    warnings.warn(w, category=PerformanceWarning, stacklevel=6)
 
                 if transpose:
                     f = partial(ti.reindex, index=reindexer, copy=False)
diff --git a/pandas/core/computation/engines.py b/pandas/core/computation/engines.py
index f45d0355e7442..155ff554cf99c 100644
--- a/pandas/core/computation/engines.py
+++ b/pandas/core/computation/engines.py
@@ -33,8 +33,9 @@ def _check_ne_builtin_clash(expr):
 
     if overlap:
         s = ', '.join(map(repr, overlap))
-        raise NumExprClobberingError('Variables in expression "%s" '
-                                     'overlap with builtins: (%s)' % (expr, s))
+        raise NumExprClobberingError('Variables in expression "{expr}" '
+                                     'overlap with builtins: ({s})'
+                                     .format(expr=expr, s=s))
 
 
 class AbstractEngine(object):
diff --git a/pandas/core/computation/eval.py b/pandas/core/computation/eval.py
index ef15e886fd554..d391764794c1c 100644
--- a/pandas/core/computation/eval.py
+++ b/pandas/core/computation/eval.py
@@ -40,8 +40,9 @@ def _check_engine(engine):
             engine = 'python'
 
     if engine not in _engines:
-        raise KeyError('Invalid engine {0!r} passed, valid engines are'
-                       ' {1}'.format(engine, list(_engines.keys())))
+        valid = list(_engines.keys())
+        raise KeyError('Invalid engine {engine!r} passed, valid engines are'
+                       ' {valid}'.format(engine=engine, valid=valid))
 
     # TODO: validate this in a more general way (thinking of future engines
     # that won't necessarily be import-able)
@@ -69,8 +70,8 @@ def _check_parser(parser):
       * If an invalid parser is passed
     """
     if parser not in _parsers:
-        raise KeyError('Invalid parser {0!r} passed, valid parsers are'
-                       ' {1}'.format(parser, _parsers.keys()))
+        raise KeyError('Invalid parser {parser!r} passed, valid parsers are'
+                       ' {valid}'.format(parser=parser, valid=_parsers.keys()))
 
 
 def _check_resolvers(resolvers):
@@ -78,8 +79,8 @@ def _check_resolvers(resolvers):
         for resolver in resolvers:
             if not hasattr(resolver, '__getitem__'):
                 name = type(resolver).__name__
-                raise TypeError('Resolver of type %r does not implement '
-                                'the __getitem__ method' % name)
+                raise TypeError('Resolver of type {name!r} does not implement '
+                                'the __getitem__ method'.format(name=name))
 
 
 def _check_expression(expr):
diff --git a/pandas/core/computation/expr.py b/pandas/core/computation/expr.py
index 73c27f4d772ca..ae956bce11329 100644
--- a/pandas/core/computation/expr.py
+++ b/pandas/core/computation/expr.py
@@ -189,8 +189,8 @@ 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 {0}'.format(_unsupported_nodes &
-                                                        _base_supported_nodes)
+_msg = 'cannot both support and not support {intersection}'.format(
+    intersection=_unsupported_nodes & _base_supported_nodes)
 assert not _unsupported_nodes & _base_supported_nodes, _msg
 
 
@@ -200,8 +200,8 @@ def _node_not_implemented(node_name, cls):
     """
 
     def f(self, *args, **kwargs):
-        raise NotImplementedError("{0!r} nodes are not "
-                                  "implemented".format(node_name))
+        raise NotImplementedError("{name!r} nodes are not "
+                                  "implemented".format(name=node_name))
     return f
 
 
@@ -217,7 +217,7 @@ def disallowed(cls):
         cls.unsupported_nodes = ()
         for node in nodes:
             new_method = _node_not_implemented(node, cls)
-            name = 'visit_{0}'.format(node)
+            name = 'visit_{node}'.format(node=node)
             cls.unsupported_nodes += (name,)
             setattr(cls, name, new_method)
         return cls
@@ -251,13 +251,14 @@ def add_ops(op_classes):
     """Decorator to add default implementation of ops."""
     def f(cls):
         for op_attr_name, op_class in compat.iteritems(op_classes):
-            ops = getattr(cls, '{0}_ops'.format(op_attr_name))
-            ops_map = getattr(cls, '{0}_op_nodes_map'.format(op_attr_name))
+            ops = getattr(cls, '{name}_ops'.format(name=op_attr_name))
+            ops_map = getattr(cls, '{name}_op_nodes_map'.format(
+                name=op_attr_name))
             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_{0}'.format(op_node), made_op)
+                    setattr(cls, 'visit_{node}'.format(node=op_node), made_op)
         return cls
     return f
 
@@ -388,9 +389,10 @@ def _maybe_evaluate_binop(self, op, op_class, lhs, rhs,
         res = op(lhs, rhs)
 
         if res.has_invalid_return_type:
-            raise TypeError("unsupported operand type(s) for {0}:"
-                            " '{1}' and '{2}'".format(res.op, lhs.type,
-                                                      rhs.type))
+            raise TypeError("unsupported operand type(s) for {op}:"
+                            " '{lhs}' and '{rhs}'".format(op=res.op,
+                                                          lhs=lhs.type,
+                                                          rhs=rhs.type))
 
         if self.engine != 'pytables':
             if (res.op in _cmp_ops_syms and
@@ -527,7 +529,8 @@ def visit_Attribute(self, node, **kwargs):
                 if isinstance(value, ast.Name) and value.id == attr:
                     return resolved
 
-        raise ValueError("Invalid Attribute context {0}".format(ctx.__name__))
+        raise ValueError("Invalid Attribute context {name}"
+                         .format(name=ctx.__name__))
 
     def visit_Call_35(self, node, side=None, **kwargs):
         """ in 3.5 the starargs attribute was changed to be more flexible,
@@ -549,7 +552,8 @@ def visit_Call_35(self, node, side=None, **kwargs):
                     raise
 
         if res is None:
-            raise ValueError("Invalid function call {0}".format(node.func.id))
+            raise ValueError("Invalid function call {func}"
+                             .format(func=node.func.id))
         if hasattr(res, 'value'):
             res = res.value
 
@@ -558,8 +562,8 @@ def visit_Call_35(self, node, side=None, **kwargs):
             new_args = [self.visit(arg) for arg in node.args]
 
             if node.keywords:
-                raise TypeError("Function \"{0}\" does not support keyword "
-                                "arguments".format(res.name))
+                raise TypeError("Function \"{name}\" does not support keyword "
+                                "arguments".format(name=res.name))
 
             return res(*new_args, **kwargs)
 
@@ -570,7 +574,7 @@ def visit_Call_35(self, node, side=None, **kwargs):
             for key in node.keywords:
                 if not isinstance(key, ast.keyword):
                     raise ValueError("keyword error in function call "
-                                     "'{0}'".format(node.func.id))
+                                     "'{func}'".format(func=node.func.id))
 
                 if key.arg:
                     # TODO: bug?
@@ -598,7 +602,8 @@ def visit_Call_legacy(self, node, side=None, **kwargs):
                     raise
 
         if res is None:
-            raise ValueError("Invalid function call {0}".format(node.func.id))
+            raise ValueError("Invalid function call {func}"
+                             .format(func=node.func.id))
         if hasattr(res, 'value'):
             res = res.value
 
@@ -609,8 +614,8 @@ def visit_Call_legacy(self, node, side=None, **kwargs):
                 args += self.visit(node.starargs)
 
             if node.keywords or node.kwargs:
-                raise TypeError("Function \"{0}\" does not support keyword "
-                                "arguments".format(res.name))
+                raise TypeError("Function \"{name}\" does not support keyword "
+                                "arguments".format(name=res.name))
 
             return res(*args, **kwargs)
 
@@ -623,7 +628,7 @@ def visit_Call_legacy(self, node, side=None, **kwargs):
             for key in node.keywords:
                 if not isinstance(key, ast.keyword):
                     raise ValueError("keyword error in function call "
-                                     "'{0}'".format(node.func.id))
+                                     "'{func}'".format(func=node.func.id))
                 keywords[key.arg] = self.visit(key.value).value
             if node.kwargs is not None:
                 keywords.update(self.visit(node.kwargs).value)
diff --git a/pandas/core/computation/expressions.py b/pandas/core/computation/expressions.py
index 83d02af65cc85..af068bd1f32b3 100644
--- a/pandas/core/computation/expressions.py
+++ b/pandas/core/computation/expressions.py
@@ -103,7 +103,7 @@ def _evaluate_numexpr(op, op_str, a, b, raise_on_error=False, truediv=True,
 
             a_value = getattr(a, "values", a)
             b_value = getattr(b, "values", b)
-            result = ne.evaluate('a_value %s b_value' % op_str,
+            result = ne.evaluate('a_value {op} b_value'.format(op=op_str),
                                  local_dict={'a_value': a_value,
                                              'b_value': b_value},
                                  casting='safe', truediv=truediv,
@@ -177,15 +177,15 @@ def _bool_arith_check(op_str, a, b, not_allowed=frozenset(('/', '//', '**')),
 
     if _has_bool_dtype(a) and _has_bool_dtype(b):
         if op_str in unsupported:
-            warnings.warn("evaluating in Python space because the %r operator"
-                          " is not supported by numexpr for the bool "
-                          "dtype, use %r instead" % (op_str,
-                                                     unsupported[op_str]))
+            warnings.warn("evaluating in Python space because the {op!r} "
+                          "operator is not supported by numexpr for "
+                          "the bool dtype, use {alt_op!r} instead"
+                          .format(op=op_str, alt_op=unsupported[op_str]))
             return False
 
         if op_str in not_allowed:
-            raise NotImplementedError("operator %r not implemented for bool "
-                                      "dtypes" % op_str)
+            raise NotImplementedError("operator {op!r} not implemented for "
+                                      "bool dtypes".format(op=op_str))
     return True
 
 
diff --git a/pandas/core/computation/pytables.py b/pandas/core/computation/pytables.py
index 5870090856ff9..4b3c608a88be8 100644
--- a/pandas/core/computation/pytables.py
+++ b/pandas/core/computation/pytables.py
@@ -41,7 +41,8 @@ def _resolve_name(self):
         # must be a queryables
         if self.side == 'left':
             if self.name not in self.env.queryables:
-                raise NameError('name {0!r} is not defined'.format(self.name))
+                raise NameError('name {name!r} is not defined'
+                                .format(name=self.name))
             return self.name
 
         # resolve the rhs (and allow it to be None)
@@ -161,7 +162,7 @@ def metadata(self):
     def generate(self, v):
         """ create and return the op string for this TermValue """
         val = v.tostring(self.encoding)
-        return "(%s %s %s)" % (self.lhs, self.op, val)
+        return "({lhs} {op} {val})".format(lhs=self.lhs, op=self.op, val=val)
 
     def convert_value(self, v):
         """ convert the expression that is in the term to something that is
@@ -215,9 +216,8 @@ def stringify(value):
             # string quoting
             return TermValue(v, stringify(v), u('string'))
         else:
-            raise TypeError(("Cannot compare {v} of type {typ}"
-                            " to {kind} column").format(v=v, typ=type(v),
-                                                        kind=kind))
+            raise TypeError("Cannot compare {v} of type {typ} to {kind} column"
+                            .format(v=v, typ=type(v), kind=kind))
 
     def convert_values(self):
         pass
@@ -226,8 +226,8 @@ def convert_values(self):
 class FilterBinOp(BinOp):
 
     def __unicode__(self):
-        return pprint_thing("[Filter : [{0}] -> "
-                            "[{1}]".format(self.filter[0], self.filter[1]))
+        return pprint_thing("[Filter : [{lhs}] -> [{op}]"
+                            .format(lhs=self.filter[0], op=self.filter[1]))
 
     def invert(self):
         """ invert the filter """
@@ -244,7 +244,8 @@ def format(self):
     def evaluate(self):
 
         if not self.is_valid:
-            raise ValueError("query term is not valid [%s]" % self)
+            raise ValueError("query term is not valid [{slf}]"
+                             .format(slf=self))
 
         rhs = self.conform(self.rhs)
         values = [TermValue(v, v, self.kind) for v in rhs]
@@ -273,9 +274,8 @@ def evaluate(self):
                 pd.Index([v.value for v in values]))
 
         else:
-            raise TypeError(
-                "passing a filterable condition to a non-table indexer [%s]" %
-                self)
+            raise TypeError("passing a filterable condition to a non-table "
+                            "indexer [{slf}]".format(slf=self))
 
         return self
 
@@ -298,7 +298,8 @@ def evaluate(self):
 class ConditionBinOp(BinOp):
 
     def __unicode__(self):
-        return pprint_thing("[Condition : [{0}]]".format(self.condition))
+        return pprint_thing("[Condition : [{cond}]]"
+                            .format(cond=self.condition))
 
     def invert(self):
         """ invert the condition """
@@ -315,7 +316,8 @@ def format(self):
     def evaluate(self):
 
         if not self.is_valid:
-            raise ValueError("query term is not valid [%s]" % self)
+            raise ValueError("query term is not valid [{slf}]"
+                             .format(slf=self))
 
         # convert values if we are in the table
         if not self.is_in_table:
@@ -330,7 +332,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 = "(%s)" % ' | '.join(vs)
+                self.condition = "({cond})".format(cond=' | '.join(vs))
 
             # use a filter after reading
             else:
@@ -344,10 +346,9 @@ def evaluate(self):
 class JointConditionBinOp(ConditionBinOp):
 
     def evaluate(self):
-        self.condition = "(%s %s %s)" % (
-            self.lhs.condition,
-            self.op,
-            self.rhs.condition)
+        self.condition = "({lhs} {op} {rhs})".format(lhs=self.lhs.condition,
+                                                     op=self.op,
+                                                     rhs=self.rhs.condition)
         return self
 
 
@@ -382,7 +383,8 @@ class ExprVisitor(BaseExprVisitor):
     def __init__(self, env, engine, parser, **kwargs):
         super(ExprVisitor, self).__init__(env, engine, parser)
         for bin_op in self.binary_ops:
-            setattr(self, 'visit_{0}'.format(self.binary_op_nodes_map[bin_op]),
+            bin_node = self.binary_op_nodes_map[bin_op]
+            setattr(self, 'visit_{node}'.format(node=bin_node),
                     lambda node, bin_op=bin_op: partial(BinOp, bin_op,
                                                         **kwargs))
 
@@ -415,8 +417,8 @@ def visit_Subscript(self, node, **kwargs):
         try:
             return self.const_type(value[slobj], self.env)
         except TypeError:
-            raise ValueError("cannot subscript {0!r} with "
-                             "{1!r}".format(value, slobj))
+            raise ValueError("cannot subscript {value!r} with "
+                             "{slobj!r}".format(value=value, slobj=slobj))
 
     def visit_Attribute(self, node, **kwargs):
         attr = node.attr
@@ -441,7 +443,8 @@ def visit_Attribute(self, node, **kwargs):
                 if isinstance(value, ast.Name) and value.id == attr:
                     return resolved
 
-        raise ValueError("Invalid Attribute context {0}".format(ctx.__name__))
+        raise ValueError("Invalid Attribute context {name}"
+                         .format(name=ctx.__name__))
 
     def translate_In(self, op):
         return ast.Eq() if isinstance(op, ast.In) else op
@@ -529,7 +532,7 @@ def __init__(self, where, queryables=None, encoding=None, scope_level=0):
                 else:
                     w = _validate_where(w)
                     where[idx] = w
-            where = ' & ' .join(["(%s)" % w for w in where])  # noqa
+            where = ' & '.join(map('({})'.format, com.flatten(where)))  # noqa
 
         self.expr = where
         self.env = Scope(scope_level + 1, local_dict=local_dict)
@@ -552,13 +555,15 @@ def evaluate(self):
         try:
             self.condition = self.terms.prune(ConditionBinOp)
         except AttributeError:
-            raise ValueError("cannot process expression [{0}], [{1}] is not a "
-                             "valid condition".format(self.expr, self))
+            raise ValueError("cannot process expression [{expr}], [{slf}] "
+                             "is not a valid condition".format(expr=self.expr,
+                                                               slf=self))
         try:
             self.filter = self.terms.prune(FilterBinOp)
         except AttributeError:
-            raise ValueError("cannot process expression [{0}], [{1}] is not a "
-                             "valid filter".format(self.expr, self))
+            raise ValueError("cannot process expression [{expr}], [{slf}] "
+                             "is not a valid filter".format(expr=self.expr,
+                                                            slf=self))
 
         return self.condition, self.filter
 
@@ -578,7 +583,7 @@ def tostring(self, encoding):
         if self.kind == u'string':
             if encoding is not None:
                 return self.converted
-            return '"%s"' % self.converted
+            return '"{converted}"'.format(converted=self.converted)
         elif self.kind == u'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 5a589473f64b7..6a298f5137eb1 100644
--- a/pandas/core/computation/scope.py
+++ b/pandas/core/computation/scope.py
@@ -137,8 +137,10 @@ def __init__(self, level, global_dict=None, local_dict=None, resolvers=(),
     def __unicode__(self):
         scope_keys = _get_pretty_string(list(self.scope.keys()))
         res_keys = _get_pretty_string(list(self.resolvers.keys()))
-        return '%s(scope=%s, resolvers=%s)' % (type(self).__name__, scope_keys,
-                                               res_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)
 
     @property
     def has_resolvers(self):
@@ -269,8 +271,9 @@ def add_tmp(self, value):
         name : basestring
             The name of the temporary variable created.
         """
-        name = '{0}_{1}_{2}'.format(type(value).__name__, self.ntemps,
-                                    _raw_hex_id(self))
+        name = '{name}_{num}_{hex_id}'.format(name=type(value).__name__,
+                                              num=self.ntemps,
+                                              hex_id=_raw_hex_id(self))
 
         # add to inner most scope
         assert name not in self.temps