diff --git a/pandas/_libs/tslibs/c_timestamp.pyx b/pandas/_libs/tslibs/c_timestamp.pyx index 2c72cec18f096..5be35c13f5737 100644 --- a/pandas/_libs/tslibs/c_timestamp.pyx +++ b/pandas/_libs/tslibs/c_timestamp.pyx @@ -59,10 +59,10 @@ def integer_op_not_supported(obj): # GH#30886 using an fstring raises SystemError int_addsub_msg = ( - "Addition/subtraction of integers and integer-arrays with {cls} is " - "no longer supported. Instead of adding/subtracting `n`, " - "use `n * obj.freq`" - ).format(cls=cls) + f"Addition/subtraction of integers and integer-arrays with {cls} is " + f"no longer supported. Instead of adding/subtracting `n`, " + f"use `n * obj.freq`" + ) return TypeError(int_addsub_msg) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 3742506a7f8af..67bc51892a4e1 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -639,7 +639,7 @@ cdef inline int64_t parse_iso_format_string(object ts) except? -1: bint have_dot = 0, have_value = 0, neg = 0 list number = [], unit = [] - err_msg = "Invalid ISO 8601 Duration format - {}".format(ts) + err_msg = f"Invalid ISO 8601 Duration format - {ts}" for c in ts: # number (ascii codes) diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 0b35a031bc53f..528cc32b7fbeb 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -1126,8 +1126,8 @@ def __arrow_array__(self, type=None): subtype = pyarrow.from_numpy_dtype(self.dtype.subtype) except TypeError: raise TypeError( - "Conversion to arrow with subtype '{}' " - "is not supported".format(self.dtype.subtype) + f"Conversion to arrow with subtype '{self.dtype.subtype}' " + f"is not supported" ) interval_type = ArrowIntervalType(subtype, self.closed) storage_array = pyarrow.StructArray.from_arrays( @@ -1155,15 +1155,13 @@ def __arrow_array__(self, type=None): # ensure we have the same subtype and closed attributes if not type.equals(interval_type): raise TypeError( - "Not supported to convert IntervalArray to type with " - "different 'subtype' ({0} vs {1}) and 'closed' ({2} vs {3}) " - "attributes".format( - self.dtype.subtype, type.subtype, self.closed, type.closed - ) + f"Not supported to convert IntervalArray to type with " + f"different 'subtype' ({self.dtype.subtype} vs {type.subtype}) " + f"and 'closed' ({self.closed} vs {type.closed}) attributes" ) else: raise TypeError( - "Not supported to convert IntervalArray to '{0}' type".format(type) + f"Not supported to convert IntervalArray to '{type}' type" ) return pyarrow.ExtensionArray.from_storage(interval_type, storage_array) @@ -1175,7 +1173,7 @@ def __arrow_array__(self, type=None): Parameters ---------- - na_tuple : boolean, default True + na_tuple : bool, default True Returns NA as a tuple if True, ``(nan, nan)``, or just as the NA value itself if False, ``nan``. diff --git a/pandas/core/util/hashing.py b/pandas/core/util/hashing.py index 3366f10b92604..b9cbc6c3ad8bd 100644 --- a/pandas/core/util/hashing.py +++ b/pandas/core/util/hashing.py @@ -295,7 +295,7 @@ def hash_array( elif issubclass(dtype.type, (np.datetime64, np.timedelta64)): vals = vals.view("i8").astype("u8", copy=False) elif issubclass(dtype.type, np.number) and dtype.itemsize <= 8: - vals = vals.view("u{}".format(vals.dtype.itemsize)).astype("u8") + vals = vals.view(f"u{vals.dtype.itemsize}").astype("u8") else: # With repeated values, its MUCH faster to categorize object dtypes, # then hash and rename categories. We allow skipping the categorization diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py index 149533bf0c238..4a429949c9a08 100644 --- a/pandas/io/formats/format.py +++ b/pandas/io/formats/format.py @@ -187,7 +187,7 @@ def _get_footer(self) -> str: if self.length: if footer: footer += ", " - footer += "Length: {length}".format(length=len(self.categorical)) + footer += f"Length: {len(self.categorical)}" level_info = self.categorical._repr_categories_info() @@ -217,7 +217,7 @@ def to_string(self) -> str: fmt_values = self._get_formatted_values() - fmt_values = ["{i}".format(i=i) for i in fmt_values] + fmt_values = [f"{i}" for i in fmt_values] fmt_values = [i.strip() for i in fmt_values] values = ", ".join(fmt_values) result = ["[" + values + "]"] @@ -301,28 +301,26 @@ def _get_footer(self) -> str: assert isinstance( self.series.index, (ABCDatetimeIndex, ABCPeriodIndex, ABCTimedeltaIndex) ) - footer += "Freq: {freq}".format(freq=self.series.index.freqstr) + footer += f"Freq: {self.series.index.freqstr}" if self.name is not False and name is not None: if footer: footer += ", " series_name = pprint_thing(name, escape_chars=("\t", "\r", "\n")) - footer += ( - ("Name: {sname}".format(sname=series_name)) if name is not None else "" - ) + footer += f"Name: {series_name}" if name is not None else "" if self.length is True or (self.length == "truncate" and self.truncate_v): if footer: footer += ", " - footer += "Length: {length}".format(length=len(self.series)) + footer += f"Length: {len(self.series)}" if self.dtype is not False and self.dtype is not None: name = getattr(self.tr_series.dtype, "name", None) if name: if footer: footer += ", " - footer += "dtype: {typ}".format(typ=pprint_thing(name)) + footer += f"dtype: {pprint_thing(name)}" # level infos are added to the end and in a new line, like it is done # for Categoricals @@ -359,9 +357,7 @@ def to_string(self) -> str: footer = self._get_footer() if len(series) == 0: - return "{name}([], {footer})".format( - name=type(self.series).__name__, footer=footer - ) + return f"{type(self.series).__name__}([], {footer})" fmt_index, have_header = self._get_formatted_index() fmt_values = self._get_formatted_values() @@ -584,10 +580,8 @@ def __init__( self.formatters = formatters else: raise ValueError( - ( - "Formatters length({flen}) should match " - "DataFrame number of columns({dlen})" - ).format(flen=len(formatters), dlen=len(frame.columns)) + f"Formatters length({len(formatters)}) should match " + f"DataFrame number of columns({len(frame.columns)})" ) self.na_rep = na_rep self.decimal = decimal @@ -816,10 +810,10 @@ def write_result(self, buf: IO[str]) -> None: frame = self.frame if len(frame.columns) == 0 or len(frame.index) == 0: - info_line = "Empty {name}\nColumns: {col}\nIndex: {idx}".format( - name=type(self.frame).__name__, - col=pprint_thing(frame.columns), - idx=pprint_thing(frame.index), + info_line = ( + f"Empty {type(self.frame).__name__}\n" + f"Columns: {pprint_thing(frame.columns)}\n" + f"Index: {pprint_thing(frame.index)}" ) text = info_line else: @@ -865,11 +859,7 @@ def write_result(self, buf: IO[str]) -> None: buf.writelines(text) if self.should_show_dimensions: - buf.write( - "\n\n[{nrows} rows x {ncols} columns]".format( - nrows=len(frame), ncols=len(frame.columns) - ) - ) + buf.write(f"\n\n[{len(frame)} rows x {len(frame.columns)} columns]") def _join_multiline(self, *args) -> str: lwidth = self.line_width @@ -1075,7 +1065,7 @@ def _get_formatted_index(self, frame: "DataFrame") -> List[str]: # empty space for columns if self.show_col_idx_names: - col_header = ["{x}".format(x=x) for x in self._get_column_name_list()] + col_header = [f"{x}" for x in self._get_column_name_list()] else: col_header = [""] * columns.nlevels @@ -1211,10 +1201,8 @@ def _format_strings(self) -> List[str]: if self.float_format is None: float_format = get_option("display.float_format") if float_format is None: - fmt_str = "{{x: .{prec:d}g}}".format( - prec=get_option("display.precision") - ) - float_format = lambda x: fmt_str.format(x=x) + precision = get_option("display.precision") + float_format = lambda x: f"{x: .{precision:d}g}" else: float_format = self.float_format @@ -1240,10 +1228,10 @@ def _format(x): pass return self.na_rep elif isinstance(x, PandasObject): - return "{x}".format(x=x) + return f"{x}" else: # object dtype - return "{x}".format(x=formatter(x)) + return f"{formatter(x)}" vals = self.values if isinstance(vals, Index): @@ -1259,7 +1247,7 @@ def _format(x): fmt_values = [] for i, v in enumerate(vals): if not is_float_type[i] and leading_space: - fmt_values.append(" {v}".format(v=_format(v))) + fmt_values.append(f" {_format(v)}") elif is_float_type[i]: fmt_values.append(float_format(v)) else: @@ -1268,8 +1256,8 @@ def _format(x): # to include a space if we get here. tpl = "{v}" else: - tpl = " {v}" - fmt_values.append(tpl.format(v=_format(v))) + tpl = f" {_format(v)}" + fmt_values.append(tpl) return fmt_values @@ -1442,7 +1430,7 @@ def _format_strings(self) -> List[str]: class IntArrayFormatter(GenericArrayFormatter): def _format_strings(self) -> List[str]: - formatter = self.formatter or (lambda x: "{x: d}".format(x=x)) + formatter = self.formatter or (lambda x: f"{x: d}") fmt_values = [formatter(x) for x in self.values] return fmt_values @@ -1726,7 +1714,7 @@ def _formatter(x): x = Timedelta(x) result = x._repr_base(format=format) if box: - result = "'{res}'".format(res=result) + result = f"'{result}'" return result return _formatter @@ -1889,16 +1877,16 @@ def __call__(self, num: Union[int, float]) -> str: prefix = self.ENG_PREFIXES[int_pow10] else: if int_pow10 < 0: - prefix = "E-{pow10:02d}".format(pow10=-int_pow10) + prefix = f"E-{-int_pow10:02d}" else: - prefix = "E+{pow10:02d}".format(pow10=int_pow10) + prefix = f"E+{int_pow10:02d}" mant = sign * dnum / (10 ** pow10) if self.accuracy is None: # pragma: no cover format_str = "{mant: g}{prefix}" else: - format_str = "{{mant: .{acc:d}f}}{{prefix}}".format(acc=self.accuracy) + format_str = f"{{mant: .{self.accuracy:d}f}}{{prefix}}" formatted = format_str.format(mant=mant, prefix=prefix) diff --git a/pandas/io/formats/html.py b/pandas/io/formats/html.py index e3161415fe2bc..3bc47cefd45c0 100644 --- a/pandas/io/formats/html.py +++ b/pandas/io/formats/html.py @@ -56,7 +56,7 @@ def __init__( self.table_id = self.fmt.table_id self.render_links = self.fmt.render_links if isinstance(self.fmt.col_space, int): - self.fmt.col_space = "{colspace}px".format(colspace=self.fmt.col_space) + self.fmt.col_space = f"{self.fmt.col_space}px" @property def show_row_idx_names(self) -> bool: @@ -124,7 +124,7 @@ def write_th( """ if header and self.fmt.col_space is not None: tags = tags or "" - tags += 'style="min-width: {colspace};"'.format(colspace=self.fmt.col_space) + tags += f'style="min-width: {self.fmt.col_space};"' self._write_cell(s, kind="th", indent=indent, tags=tags) @@ -135,9 +135,9 @@ def _write_cell( self, s: Any, kind: str = "td", indent: int = 0, tags: Optional[str] = None ) -> None: if tags is not None: - start_tag = "<{kind} {tags}>".format(kind=kind, tags=tags) + start_tag = f"<{kind} {tags}>" else: - start_tag = "<{kind}>".format(kind=kind) + start_tag = f"<{kind}>" if self.escape: # escape & first to prevent double escaping of & @@ -149,16 +149,13 @@ def _write_cell( if self.render_links and is_url(rs): rs_unescaped = pprint_thing(s, escape_chars={}).strip() - start_tag += ''.format(url=rs_unescaped) + start_tag += f'' end_a = "" else: end_a = "" self.write( - "{start}{rs}{end_a}".format( - start=start_tag, rs=rs, end_a=end_a, kind=kind - ), - indent, + f"{start_tag}{rs}{end_a}", indent, ) def write_tr( @@ -177,7 +174,7 @@ def write_tr( if align is None: self.write("", indent) else: - self.write(''.format(align=align), indent) + self.write(f'', indent) indent += indent_delta for i, s in enumerate(line): @@ -196,9 +193,7 @@ def render(self) -> List[str]: if self.should_show_dimensions: by = chr(215) # × self.write( - "

{rows} rows {by} {cols} columns

".format( - rows=len(self.frame), by=by, cols=len(self.frame.columns) - ) + f"

{len(self.frame)} rows {by} {len(self.frame.columns)} columns

" ) return self.elements @@ -216,7 +211,7 @@ def _write_table(self, indent: int = 0) -> None: self.classes = self.classes.split() if not isinstance(self.classes, (list, tuple)): raise TypeError( - "classes must be a string, list, " + f"classes must be a string, list, " f"or tuple, not {type(self.classes)}" ) _classes.extend(self.classes) @@ -224,12 +219,10 @@ def _write_table(self, indent: int = 0) -> None: if self.table_id is None: id_section = "" else: - id_section = ' id="{table_id}"'.format(table_id=self.table_id) + id_section = f' id="{self.table_id}"' self.write( - ''.format( - border=self.border, cls=" ".join(_classes), id_section=id_section - ), + f'
', indent, ) diff --git a/pandas/io/formats/latex.py b/pandas/io/formats/latex.py index 8ab56437d5c05..c6d2055ecfea8 100644 --- a/pandas/io/formats/latex.py +++ b/pandas/io/formats/latex.py @@ -59,10 +59,9 @@ def write_result(self, buf: IO[str]) -> None: # string representation of the columns if len(self.frame.columns) == 0 or len(self.frame.index) == 0: - info_line = "Empty {name}\nColumns: {col}\nIndex: {idx}".format( - name=type(self.frame).__name__, - col=self.frame.columns, - idx=self.frame.index, + info_line = ( + f"Empty {type(self.frame).__name__}\n" + f"Columns: {self.frame.columns}\nIndex: {self.frame.index}" ) strcols = [[info_line]] else: @@ -141,8 +140,8 @@ def pad_empties(x): buf.write("\\endhead\n") buf.write("\\midrule\n") buf.write( - "\\multicolumn{{{n}}}{{r}}{{{{Continued on next " - "page}}}} \\\\\n".format(n=len(row)) + f"\\multicolumn{{{len(row)}}}{{r}}{{{{Continued on next " + f"page}}}} \\\\\n" ) buf.write("\\midrule\n") buf.write("\\endfoot\n\n") @@ -172,7 +171,7 @@ def pad_empties(x): if self.bold_rows and self.fmt.index: # bold row labels crow = [ - "\\textbf{{{x}}}".format(x=x) + f"\\textbf{{{x}}}" if j < ilevels and x.strip() not in ["", "{}"] else x for j, x in enumerate(crow) @@ -211,9 +210,8 @@ def append_col(): # write multicolumn if needed if ncol > 1: row2.append( - "\\multicolumn{{{ncol:d}}}{{{fmt:s}}}{{{txt:s}}}".format( - ncol=ncol, fmt=self.multicolumn_format, txt=coltext.strip() - ) + f"\\multicolumn{{{ncol:d}}}{{{self.multicolumn_format:s}}}" + f"{{{coltext.strip():s}}}" ) # don't modify where not needed else: @@ -256,9 +254,7 @@ def _format_multirow( break if nrow > 1: # overwrite non-multirow entry - row[j] = "\\multirow{{{nrow:d}}}{{*}}{{{row:s}}}".format( - nrow=nrow, row=row[j].strip() - ) + row[j] = f"\\multirow{{{nrow:d}}}{{*}}{{{row[j].strip():s}}}" # save when to end the current block with \cline self.clinebuf.append([i + nrow - 1, j + 1]) return row @@ -269,7 +265,7 @@ def _print_cline(self, buf: IO[str], i: int, icol: int) -> None: """ for cl in self.clinebuf: if cl[0] == i: - buf.write("\\cline{{{cl:d}-{icol:d}}}\n".format(cl=cl[1], icol=icol)) + buf.write(f"\\cline{{{cl[1]:d}-{icol:d}}}\n") # remove entries that have been written to buffer self.clinebuf = [x for x in self.clinebuf if x[0] != i] @@ -293,19 +289,19 @@ def _write_tabular_begin(self, buf, column_format: str): if self.caption is None: caption_ = "" else: - caption_ = "\n\\caption{{{}}}".format(self.caption) + caption_ = f"\n\\caption{{{self.caption}}}" if self.label is None: label_ = "" else: - label_ = "\n\\label{{{}}}".format(self.label) + label_ = f"\n\\label{{{self.label}}}" - buf.write("\\begin{{table}}\n\\centering{}{}\n".format(caption_, label_)) + buf.write(f"\\begin{{table}}\n\\centering{caption_}{label_}\n") else: # then write output only in a tabular environment pass - buf.write("\\begin{{tabular}}{{{fmt}}}\n".format(fmt=column_format)) + buf.write(f"\\begin{{tabular}}{{{column_format}}}\n") def _write_tabular_end(self, buf): """ @@ -341,18 +337,18 @@ def _write_longtable_begin(self, buf, column_format: str): `__ e.g 'rcl' for 3 columns """ - buf.write("\\begin{{longtable}}{{{fmt}}}\n".format(fmt=column_format)) + buf.write(f"\\begin{{longtable}}{{{column_format}}}\n") if self.caption is not None or self.label is not None: if self.caption is None: pass else: - buf.write("\\caption{{{}}}".format(self.caption)) + buf.write(f"\\caption{{{self.caption}}}") if self.label is None: pass else: - buf.write("\\label{{{}}}".format(self.label)) + buf.write(f"\\label{{{self.label}}}") # a double-backslash is required at the end of the line # as discussed here: diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py index 13b18a0b5fb6f..36e774305b577 100644 --- a/pandas/io/formats/printing.py +++ b/pandas/io/formats/printing.py @@ -229,7 +229,7 @@ def as_escaped_string( max_seq_items=max_seq_items, ) elif isinstance(thing, str) and quote_strings: - result = "'{thing}'".format(thing=as_escaped_string(thing)) + result = f"'{as_escaped_string(thing)}'" else: result = as_escaped_string(thing) diff --git a/pandas/io/parsers.py b/pandas/io/parsers.py index 8bc8470ae7658..b661770dc80a2 100755 --- a/pandas/io/parsers.py +++ b/pandas/io/parsers.py @@ -89,7 +89,7 @@ ---------- filepath_or_buffer : str, path object or file-like object Any valid string path is acceptable. The string could be a URL. Valid - URL schemes include http, ftp, s3, and file. For file URLs, a host is + URL schemes include http, ftp, s3, gs, and file. For file URLs, a host is expected. A local file could be: file://localhost/path/to/table.csv. If you want to pass in a path object, pandas accepts any ``os.PathLike``. @@ -1493,10 +1493,8 @@ def extract(r): for n in range(len(columns[0])): if all(ensure_str(col[n]) in self.unnamed_cols for col in columns): raise ParserError( - "Passed header=[{header}] are too many rows for this " - "multi_index of columns".format( - header=",".join(str(x) for x in self.header) - ) + f"Passed header=[{','.join(str(x) for x in self.header)}] " + f"are too many rows for this multi_index of columns" ) # Clean the column names (if we have an index_col). @@ -3613,8 +3611,8 @@ def get_rows(self, infer_nrows, skiprows=None): def detect_colspecs(self, infer_nrows=100, skiprows=None): # Regex escape the delimiters - delimiters = "".join(r"\{}".format(x) for x in self.delimiter) - pattern = re.compile("([^{}]+)".format(delimiters)) + delimiters = "".join(fr"\{x}" for x in self.delimiter) + pattern = re.compile(f"([^{delimiters}]+)") rows = self.get_rows(infer_nrows, skiprows) if not rows: raise EmptyDataError("No rows from which to infer column width") diff --git a/pandas/tests/arrays/categorical/test_dtypes.py b/pandas/tests/arrays/categorical/test_dtypes.py index 19746d7d72162..9922a8863ebc2 100644 --- a/pandas/tests/arrays/categorical/test_dtypes.py +++ b/pandas/tests/arrays/categorical/test_dtypes.py @@ -92,22 +92,20 @@ def test_codes_dtypes(self): result = Categorical(["foo", "bar", "baz"]) assert result.codes.dtype == "int8" - result = Categorical(["foo{i:05d}".format(i=i) for i in range(400)]) + result = Categorical([f"foo{i:05d}" for i in range(400)]) assert result.codes.dtype == "int16" - result = Categorical(["foo{i:05d}".format(i=i) for i in range(40000)]) + result = Categorical([f"foo{i:05d}" for i in range(40000)]) assert result.codes.dtype == "int32" # adding cats result = Categorical(["foo", "bar", "baz"]) assert result.codes.dtype == "int8" - result = result.add_categories(["foo{i:05d}".format(i=i) for i in range(400)]) + result = result.add_categories([f"foo{i:05d}" for i in range(400)]) assert result.codes.dtype == "int16" # removing cats - result = result.remove_categories( - ["foo{i:05d}".format(i=i) for i in range(300)] - ) + result = result.remove_categories([f"foo{i:05d}" for i in range(300)]) assert result.codes.dtype == "int8" @pytest.mark.parametrize("ordered", [True, False]) diff --git a/pandas/tests/arrays/categorical/test_operators.py b/pandas/tests/arrays/categorical/test_operators.py index 0c830c65e0f8b..c3006687ca6dd 100644 --- a/pandas/tests/arrays/categorical/test_operators.py +++ b/pandas/tests/arrays/categorical/test_operators.py @@ -338,7 +338,7 @@ def test_compare_unordered_different_order(self): def test_numeric_like_ops(self): df = DataFrame({"value": np.random.randint(0, 10000, 100)}) - labels = ["{0} - {1}".format(i, i + 499) for i in range(0, 10000, 500)] + labels = [f"{i} - {i + 499}" for i in range(0, 10000, 500)] cat_labels = Categorical(labels, labels) df = df.sort_values(by=["value"], ascending=True) @@ -353,9 +353,7 @@ def test_numeric_like_ops(self): ("__mul__", r"\*"), ("__truediv__", "/"), ]: - msg = r"Series cannot perform the operation {}|unsupported operand".format( - str_rep - ) + msg = fr"Series cannot perform the operation {str_rep}|unsupported operand" with pytest.raises(TypeError, match=msg): getattr(df, op)(df) @@ -363,7 +361,7 @@ def test_numeric_like_ops(self): # min/max) s = df["value_group"] for op in ["kurt", "skew", "var", "std", "mean", "sum", "median"]: - msg = "Categorical cannot perform the operation {}".format(op) + msg = f"Categorical cannot perform the operation {op}" with pytest.raises(TypeError, match=msg): getattr(s, op)(numeric_only=False) @@ -383,9 +381,7 @@ def test_numeric_like_ops(self): ("__mul__", r"\*"), ("__truediv__", "/"), ]: - msg = r"Series cannot perform the operation {}|unsupported operand".format( - str_rep - ) + msg = fr"Series cannot perform the operation {str_rep}|unsupported operand" with pytest.raises(TypeError, match=msg): getattr(s, op)(2)