diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index fdf4059fad569..f3d51b28ad399 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -596,7 +596,7 @@ def _format_native_types(self, na_rep="NaT", date_format=None, **kwargs): if date_format: formatter = lambda dt: dt.strftime(date_format) else: - formatter = lambda dt: "%s" % dt + formatter = lambda dt: str(dt) if self._hasnans: mask = self._isnan diff --git a/pandas/core/common.py b/pandas/core/common.py index 133e60de5d694..41b6ebbd2f196 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -451,7 +451,7 @@ def pipe(obj, func, *args, **kwargs): if isinstance(func, tuple): func, target = func if target in kwargs: - msg = "%s is both the pipe target and a keyword argument" % target + msg = f"{target} is both the pipe target and a keyword argument" raise ValueError(msg) kwargs[target] = obj return func(*args, **kwargs) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 442994a04caee..ad970cac92724 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1805,7 +1805,7 @@ def to_records( if isinstance(self.index, ABCMultiIndex): for i, n in enumerate(index_names): if n is None: - index_names[i] = "level_%d" % count + index_names[i] = f"level_{count}" count += 1 elif index_names[0] is None: index_names = ["index"] @@ -2454,7 +2454,7 @@ def info( exceeds_info_cols = len(self.columns) > max_cols def _verbose_repr(): - lines.append("Data columns (total %d columns):" % len(self.columns)) + lines.append(f"Data columns (total {len(self.columns)} columns):") space = max(len(pprint_thing(k)) for k in self.columns) + 4 counts = None @@ -2846,7 +2846,7 @@ def _getitem_bool_array(self, key): ) elif len(key) != len(self.index): raise ValueError( - "Item wrong length %d instead of %d." % (len(key), len(self.index)) + f"Item wrong length {len(key)} instead of {len(self.index)}." ) # check_bool_indexer will throw exception if Series key cannot @@ -2957,7 +2957,7 @@ def _setitem_array(self, key, value): if com.is_bool_indexer(key): if len(key) != len(self.index): raise ValueError( - "Item wrong length %d instead of %d!" % (len(key), len(self.index)) + f"Item wrong length {len(key)} instead of {len(self.index)}!" ) key = check_bool_indexer(self.index, key) indexer = key.nonzero()[0] @@ -4537,8 +4537,8 @@ def _maybe_casted_values(index, labels=None): if not drop: if isinstance(self.index, ABCMultiIndex): names = [ - n if n is not None else ("level_%d" % i) - for (i, n) in enumerate(self.index.names) + (n if n is not None else f"level_{i}") + for i, n in enumerate(self.index.names) ] to_insert = zip(self.index.levels, self.index.codes) else: @@ -4858,8 +4858,7 @@ def sort_values( by = [by] if is_sequence(ascending) and len(by) != len(ascending): raise ValueError( - "Length of ascending (%d) != length of by (%d)" - % (len(ascending), len(by)) + f"Length of ascending ({len(ascending)}) != length of by ({len(by)})" ) if len(by) > 1: from pandas.core.sorting import lexsort_indexer diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 17784b623c414..e9964167c7c10 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -421,8 +421,7 @@ def _construct_axes_from_arguments( if a in kwargs: if alias in kwargs: raise TypeError( - "arguments are mutually exclusive " - "for [%s,%s]" % (a, alias) + f"arguments are mutually exclusive for [{a},{alias}]" ) continue if alias in kwargs: @@ -754,7 +753,7 @@ def transpose(self, *args, **kwargs): # we must have unique axes if len(axes) != len(set(axes)): - raise ValueError("Must specify %s unique axes" % self._AXIS_LEN) + raise ValueError(f"Must specify {self._AXIS_LEN} unique axes") new_axes = self._construct_axes_dict_from( self, [self._get_axis(x) for x in axes_names] @@ -2096,7 +2095,7 @@ def __repr__(self) -> str: # string representation based upon iterating over self # (since, by definition, `PandasContainers` are iterable) prepr = "[%s]" % ",".join(map(pprint_thing, self)) - return "%s(%s)" % (self.__class__.__name__, prepr) + return f"{self.__class__.__name__}({prepr})" def _repr_latex_(self): """ @@ -6357,7 +6356,7 @@ def fillna( elif isinstance(value, ABCDataFrame) and self.ndim == 2: new_data = self.where(self.notna(), value) else: - raise ValueError("invalid fill value with a %s" % type(value)) + raise ValueError(f"invalid fill value with a {type(value)}") if inplace: self._update_inplace(new_data) @@ -6794,9 +6793,8 @@ def replace( if is_list_like(value): if len(to_replace) != len(value): raise ValueError( - "Replacement lists must match " - "in length. Expecting %d got %d " - % (len(to_replace), len(value)) + f"Replacement lists must match in length. " + f"Expecting {len(to_replace)} got {len(value)} " ) new_data = self._data.replace_list( @@ -8871,7 +8869,7 @@ def align( fill_axis=fill_axis, ) else: # pragma: no cover - raise TypeError("unsupported type: %s" % type(other)) + raise TypeError(f"unsupported type: {type(other)}") def _align_frame( self, @@ -9515,9 +9513,9 @@ def tshift(self, periods=1, freq=None, axis=0): new_data = self._data.copy() new_data.axes[block_axis] = index.shift(periods) else: - msg = "Given freq %s does not match PeriodIndex freq %s" % ( - freq.rule_code, - orig_freq.rule_code, + msg = ( + f"Given freq {freq.rule_code} does not match" + f" PeriodIndex freq {orig_freq.rule_code}" ) raise ValueError(msg) else: @@ -9665,7 +9663,7 @@ def truncate(self, before=None, after=None, axis=None, copy=True): if before is not None and after is not None: if before > after: - raise ValueError("Truncate: %s must be after %s" % (after, before)) + raise ValueError(f"Truncate: {after} must be after {before}") slicer = [slice(None, None)] * self._AXIS_LEN slicer[axis] = slice(before, after) @@ -9711,7 +9709,7 @@ def _tz_convert(ax, tz): if len(ax) > 0: ax_name = self._get_axis_name(axis) raise TypeError( - "%s is not a valid DatetimeIndex or PeriodIndex" % ax_name + f"{ax_name} is not a valid DatetimeIndex or PeriodIndex" ) else: ax = DatetimeIndex([], tz=tz) @@ -9875,7 +9873,7 @@ def _tz_localize(ax, tz, ambiguous, nonexistent): if len(ax) > 0: ax_name = self._get_axis_name(axis) raise TypeError( - "%s is not a valid DatetimeIndex or PeriodIndex" % ax_name + f"{ax_name} is not a valid DatetimeIndex or PeriodIndex" ) else: ax = DatetimeIndex([], tz=tz) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index a8c7100b3846a..88f26a4df65ef 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -963,14 +963,14 @@ def __repr__(self): data = self._format_data() attrs = self._format_attrs() space = self._format_space() - - prepr = (",%s" % space).join("%s=%s" % (k, v) for k, v in attrs) + attrs_str = [f"{k}={v}" for k, v in attrs] + prepr = f",{space}".join(attrs_str) # no data provided, just attributes if data is None: data = "" - res = "%s(%s%s)" % (klass, data, prepr) + res = f"{klass}({data}{prepr})" return res @@ -1124,13 +1124,13 @@ def _summary(self, name=None): tail = self[-1] if hasattr(tail, "format") and not isinstance(tail, str): tail = tail.format() - index_summary = ", %s to %s" % (pprint_thing(head), pprint_thing(tail)) + index_summary = f", {head} to {tail}" else: index_summary = "" if name is None: name = type(self).__name__ - return "%s: %s entries%s" % (name, len(self), index_summary) + return f"{name}: {len(self)} entries{index_summary}" def summary(self, name=None): """ @@ -1304,7 +1304,7 @@ def _set_names(self, values, level=None): if not is_list_like(values): raise ValueError("Names must be a list-like") if len(values) != 1: - raise ValueError("Length of new names must be 1, got %d" % len(values)) + raise ValueError(f"Length of new names must be 1, got {len(values)}") # GH 20527 # All items in 'name' need to be hashable: @@ -1475,8 +1475,8 @@ def _validate_index_level(self, level): if isinstance(level, int): if level < 0 and level != -1: raise IndexError( - "Too many levels: Index has only 1 level," - " %d is not a valid level number" % (level,) + f"Too many levels: Index has only 1 level," + f" {level} is not a valid level number" ) elif level > 0: raise IndexError( @@ -4565,7 +4565,7 @@ def shift(self, periods=1, freq=None): '2012-03-01'], dtype='datetime64[ns]', freq='MS') """ - raise NotImplementedError("Not supported for type %s" % type(self).__name__) + raise NotImplementedError(f"Not supported for type {type(self).__name__}") def argsort(self, *args, **kwargs): """ @@ -5072,8 +5072,8 @@ def get_slice_bound(self, label, side, kind): if side not in ("left", "right"): raise ValueError( - "Invalid value for side kwarg," - " must be either 'left' or 'right': %s" % (side,) + f"Invalid value for side kwarg, must be either" + f" 'left' or 'right': {side}" ) original_label = label @@ -5627,7 +5627,7 @@ def _trim_front(strings): def _validate_join_method(method): if method not in ["left", "right", "inner", "outer"]: - raise ValueError("do not recognize join method %s" % method) + raise ValueError(f"do not recognize join method {method}") def default_index(n): diff --git a/pandas/core/indexes/category.py b/pandas/core/indexes/category.py index 819f8ac53197a..e0ffc726bc3a1 100644 --- a/pandas/core/indexes/category.py +++ b/pandas/core/indexes/category.py @@ -357,7 +357,7 @@ def _format_attrs(self): ] if self.name is not None: attrs.append(("name", ibase.default_pprint(self.name))) - attrs.append(("dtype", "'%s'" % self.dtype.name)) + attrs.append(("dtype", f"'{self.dtype.name}'")) max_seq_items = get_option("display.max_seq_items") or len(self) if len(self) > max_seq_items: attrs.append(("length", len(self))) diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index ceb23f61ae15a..b8670b765ca90 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -36,7 +36,6 @@ from pandas.core.indexes.base import Index, _index_shared_docs from pandas.core.tools.timedeltas import to_timedelta -import pandas.io.formats.printing as printing from pandas.tseries.frequencies import to_offset _index_doc_kwargs = dict(ibase._index_doc_kwargs) @@ -496,7 +495,7 @@ def _format_attrs(self): if attrib == "freq": freq = self.freqstr if freq is not None: - freq = "'%s'" % freq + freq = f"{freq!r}" attrs.append(("freq", freq)) return attrs @@ -686,17 +685,13 @@ def _summary(self, name=None): """ formatter = self._formatter_func if len(self) > 0: - index_summary = ", %s to %s" % (formatter(self[0]), formatter(self[-1])) + index_summary = f", {formatter(self[0])} to {formatter(self[-1])}" else: index_summary = "" if name is None: name = type(self).__name__ - result = "%s: %s entries%s" % ( - printing.pprint_thing(name), - len(self), - index_summary, - ) + result = f"{name}: {len(self)} entries{index_summary}" if self.freq: result += "\nFreq: %s" % self.freqstr diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index 41f5eb90d51b0..4a95f0a2ab7e9 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -491,7 +491,7 @@ def _formatter_func(self): from pandas.io.formats.format import _get_format_datetime64 formatter = _get_format_datetime64(is_dates_only=self._is_dates_only) - return lambda x: "'%s'" % formatter(x, tz=self.tz) + return lambda x: f"'{formatter(x, tz=self.tz)}'" # -------------------------------------------------------------------- # Set Operation Methods diff --git a/pandas/core/indexes/frozen.py b/pandas/core/indexes/frozen.py index 08c86b81b59c0..1b33269d404d6 100644 --- a/pandas/core/indexes/frozen.py +++ b/pandas/core/indexes/frozen.py @@ -109,7 +109,7 @@ def __str__(self) -> str: return pprint_thing(self, quote_strings=True, escape_chars=("\t", "\r", "\n")) def __repr__(self) -> str: - return "%s(%s)" % (self.__class__.__name__, str(self)) + return f"{self.__class__.__name__}({str(self)})" __setitem__ = __setslice__ = __delitem__ = __delslice__ = _disabled pop = append = extend = remove = sort = insert = _disabled @@ -153,7 +153,7 @@ def __repr__(self) -> str: Return a string representation for this object. """ prepr = pprint_thing(self, escape_chars=("\t", "\r", "\n"), quote_strings=True) - return "%s(%s, dtype='%s')" % (type(self).__name__, prepr, self.dtype) + return f"{type(self).__name__}({prepr}, dtype='{self.dtype}')" @deprecate_kwarg(old_arg_name="v", new_arg_name="value") def searchsorted(self, value, side="left", sorter=None): diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index f3a735511c96b..86398613798be 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -1329,21 +1329,20 @@ def _get_level_number(self, level) -> int: count = self.names.count(level) if (count > 1) and not is_integer(level): raise ValueError( - "The name %s occurs multiple times, use a level number" % level + f"The name {level} occurs multiple times, use a level number" ) try: level = self.names.index(level) except ValueError: if not is_integer(level): - raise KeyError("Level %s not found" % str(level)) + raise KeyError(f"Level {level} not found") elif level < 0: level += self.nlevels if level < 0: orig_level = level - self.nlevels raise IndexError( - "Too many levels: Index has only %d " - "levels, %d is not a valid level number" - % (self.nlevels, orig_level) + f"Too many levels: Index has only {self.nlevels} levels," + f" {orig_level} is not a valid level number" ) # Note: levels are zero-based elif level >= self.nlevels: @@ -2286,8 +2285,8 @@ def reorder_levels(self, order): order = [self._get_level_number(i) for i in order] if len(order) != self.nlevels: raise AssertionError( - "Length of order must be same as " - "number of levels (%d), got %d" % (self.nlevels, len(order)) + f"Length of order must be same as number of levels ({self.nlevels})," + f" got {len(order)}" ) new_levels = [self.levels[i] for i in order] new_codes = [self.codes[i] for i in order] @@ -2599,8 +2598,8 @@ def slice_locs(self, start=None, end=None, step=None, kind=None): def _partial_tup_index(self, tup, side="left"): if len(tup) > self.lexsort_depth: raise UnsortedIndexError( - "Key length (%d) was greater than MultiIndex" - " lexsort depth (%d)" % (len(tup), self.lexsort_depth) + f"Key length ({len(tup)}) was greater than MultiIndex lexsort depth" + f" ({self.lexsort_depth})" ) n = len(tup) @@ -2611,7 +2610,7 @@ def _partial_tup_index(self, tup, side="left"): if lab not in lev: if not lev.is_type_compatible(lib.infer_dtype([lab], skipna=False)): - raise TypeError("Level type mismatch: %s" % lab) + raise TypeError(f"Level type mismatch: {lab}") # short circuit loc = lev.searchsorted(lab, side=side) diff --git a/pandas/core/series.py b/pandas/core/series.py index d771aefb55844..3f69dd53491c1 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1008,7 +1008,7 @@ def _unpickle_series_compat(self, state): self.name = name else: - raise Exception("cannot unpickle legacy formats -> [%s]" % state) + raise Exception(f"cannot unpickle legacy formats -> [{state}]") # indexers @property @@ -1303,7 +1303,7 @@ def _set_labels(self, key, value): indexer = self.index.get_indexer(key) mask = indexer == -1 if mask.any(): - raise ValueError("%s not contained in the index" % str(key[mask])) + raise ValueError(f"{key[mask]} not contained in the index") self._set_values(indexer, value) def _set_values(self, key, value): @@ -2591,7 +2591,7 @@ def dot(self, other): rvals = np.asarray(other) if lvals.shape[0] != rvals.shape[0]: raise Exception( - "Dot product shape mismatch, %s vs %s" % (lvals.shape, rvals.shape) + f"Dot product shape mismatch, {lvals.shape} vs {rvals.shape}" ) if isinstance(other, ABCDataFrame): @@ -2603,7 +2603,7 @@ def dot(self, other): elif isinstance(rvals, np.ndarray): return np.dot(lvals, rvals) else: # pragma: no cover - raise TypeError("unsupported type: %s" % type(other)) + raise TypeError(f"unsupported type: {type(other)}") def __matmul__(self, other): """ @@ -3083,8 +3083,7 @@ def _try_kind_sort(arr): if is_list_like(ascending): if len(ascending) != 1: raise ValueError( - "Length of ascending (%d) must be 1 " - "for Series" % (len(ascending)) + f"Length of ascending ({len(ascending)}) must be 1 for Series" ) ascending = ascending[0] diff --git a/pandas/core/util/hashing.py b/pandas/core/util/hashing.py index 23c370638b572..fa3582755a202 100644 --- a/pandas/core/util/hashing.py +++ b/pandas/core/util/hashing.py @@ -133,7 +133,7 @@ def hash_pandas_object( h = Series(h, index=obj.index, dtype="uint64", copy=False) else: - raise TypeError("Unexpected type for hashing %s" % type(obj)) + raise TypeError(f"Unexpected type for hashing {type(obj)}") return h diff --git a/pandas/io/clipboard/__init__.py b/pandas/io/clipboard/__init__.py index 40452b41998df..4f690a57893d1 100644 --- a/pandas/io/clipboard/__init__.py +++ b/pandas/io/clipboard/__init__.py @@ -87,7 +87,7 @@ class PyperclipException(RuntimeError): class PyperclipWindowsException(PyperclipException): def __init__(self, message): - message += " (%s)" % ctypes.WinError() + message += f" ({ctypes.WinError()})" super().__init__(message) @@ -599,9 +599,9 @@ def set_clipboard(clipboard): } if clipboard not in clipboard_types: + allowed_clipboard_types = [repr(_) for _ in clipboard_types.keys()] raise ValueError( - "Argument must be one of %s" - % (", ".join([repr(_) for _ in clipboard_types.keys()])) + f"Argument must be one of {', '.join(allowed_clipboard_types)}" ) # Sets pyperclip's copy() and paste() functions: diff --git a/pandas/io/sas/sas_xport.py b/pandas/io/sas/sas_xport.py index 2f2dbdbc76215..9aa8ed1dfeb5d 100644 --- a/pandas/io/sas/sas_xport.py +++ b/pandas/io/sas/sas_xport.py @@ -482,7 +482,7 @@ def read(self, nrows=None): df = pd.DataFrame(index=range(read_lines)) for j, x in enumerate(self.columns): - vec = data["s%d" % j] + vec = data["s" + str(j)] ntype = self.fields[j]["ntype"] if ntype == "numeric": vec = _handle_truncated_float_vec(vec, self.fields[j]["field_length"]) diff --git a/pandas/io/stata.py b/pandas/io/stata.py index d51c9170c488b..d4d378573b54e 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -2640,7 +2640,7 @@ def _dtype_to_stata_type_117(dtype, column, force_strl): elif dtype == np.int8: return 65530 else: # pragma : no cover - raise NotImplementedError("Data type %s not supported." % dtype) + raise NotImplementedError(f"Data type {dtype} not supported.") def _pad_bytes_new(name, length): diff --git a/pandas/plotting/_matplotlib/converter.py b/pandas/plotting/_matplotlib/converter.py index 946ce8bcec97f..4b0ba2bd423df 100644 --- a/pandas/plotting/_matplotlib/converter.py +++ b/pandas/plotting/_matplotlib/converter.py @@ -429,7 +429,8 @@ def __call__(self): ).format(estimate=estimate, dmin=dmin, dmax=dmax, arg=self.MAXTICKS * 2) ) - freq = "%dL" % self._get_interval() + interval = self._get_interval() + freq = f"{interval}L" tz = self.tz.tzname(None) st = _from_ordinal(dates.date2num(dmin)) # strip tz ed = _from_ordinal(dates.date2num(dmax)) diff --git a/pandas/tests/frame/test_query_eval.py b/pandas/tests/frame/test_query_eval.py index 04d27f4c12c59..cd1bee356ed8e 100644 --- a/pandas/tests/frame/test_query_eval.py +++ b/pandas/tests/frame/test_query_eval.py @@ -991,7 +991,7 @@ def test_query_lex_compare_strings(self, parser, engine): ops = {"<": operator.lt, ">": operator.gt, "<=": operator.le, ">=": operator.ge} for op, func in ops.items(): - res = df.query('X %s "d"' % op, engine=engine, parser=parser) + res = df.query(f'X {op} "d"', engine=engine, parser=parser) expected = df[func(df.X, "d")] tm.assert_frame_equal(res, expected) diff --git a/pandas/tests/internals/test_internals.py b/pandas/tests/internals/test_internals.py index fa7a98c617677..dbd84f15d143c 100644 --- a/pandas/tests/internals/test_internals.py +++ b/pandas/tests/internals/test_internals.py @@ -134,7 +134,7 @@ def create_block(typestr, placement, item_shape=None, num_offset=0): arr = values.sp_values.view() arr += num_offset - 1 else: - raise ValueError('Unsupported typestr: "%s"' % typestr) + raise ValueError(f'Unsupported typestr: "{typestr}"') return make_block(values, placement=placement, ndim=len(shape)) diff --git a/pandas/tests/io/formats/test_style.py b/pandas/tests/io/formats/test_style.py index e5af74bdd4d33..61a3934187bd3 100644 --- a/pandas/tests/io/formats/test_style.py +++ b/pandas/tests/io/formats/test_style.py @@ -390,7 +390,7 @@ def test_applymap_subset_multiindex_code(self): def color_negative_red(val): color = "red" if val < 0 else "black" - return "color: %s" % color + return f"color: {color}" df.loc[pct_subset] df.style.applymap(color_negative_red, subset=pct_subset) diff --git a/pandas/tests/util/test_validate_kwargs.py b/pandas/tests/util/test_validate_kwargs.py index ec9f3948403de..b6241def4e5d6 100644 --- a/pandas/tests/util/test_validate_kwargs.py +++ b/pandas/tests/util/test_validate_kwargs.py @@ -60,9 +60,9 @@ def test_validation(): @pytest.mark.parametrize("name", ["inplace", "copy"]) @pytest.mark.parametrize("value", [1, "True", [1, 2, 3], 5.0]) def test_validate_bool_kwarg_fail(name, value): - msg = 'For argument "%s" expected type bool, received type %s' % ( - name, - type(value).__name__, + msg = ( + f'For argument "{name}" expected type bool,' + f" received type {type(value).__name__}" ) with pytest.raises(ValueError, match=msg): diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py index b516c3d78a11e..b9c165140aaad 100644 --- a/pandas/util/_test_decorators.py +++ b/pandas/util/_test_decorators.py @@ -199,7 +199,7 @@ def skip_if_no(package: str, min_version: Optional[str] = None) -> Callable: def skip_if_np_lt(ver_str, reason=None, *args, **kwds): if reason is None: - reason = "NumPy %s or greater required" % ver_str + reason = f"NumPy {ver_str} or greater required" return pytest.mark.skipif( _np_version < LooseVersion(ver_str), reason=reason, *args, **kwds )