From bfec4bbb3185409425e7f002b51c77a97d6fb004 Mon Sep 17 00:00:00 2001 From: Thomas Li Date: Thu, 12 Dec 2019 16:39:52 -0800 Subject: [PATCH 1/3] CLN: use f-strings instead in pandas/util subdir --- pandas/util/_decorators.py | 19 +++++++---------- pandas/util/_depr_module.py | 20 +++++++----------- pandas/util/_doctools.py | 2 +- pandas/util/_print_versions.py | 14 ++++++------- pandas/util/_test_decorators.py | 15 ++++++------- pandas/util/_validators.py | 37 ++++++++++++--------------------- 6 files changed, 42 insertions(+), 65 deletions(-) diff --git a/pandas/util/_decorators.py b/pandas/util/_decorators.py index 2684b90e33b7e..2e91d76b0fe98 100644 --- a/pandas/util/_decorators.py +++ b/pandas/util/_decorators.py @@ -84,18 +84,13 @@ def wrapper(*args, **kwargs) -> Callable[..., Any]: if empty1 or empty2 and not summary: raise AssertionError(doc_error_msg) wrapper.__doc__ = dedent( - """ - {summary} - - .. deprecated:: {depr_version} - {depr_msg} - - {rest_of_docstring}""" - ).format( - summary=summary.strip(), - depr_version=version, - depr_msg=msg, - rest_of_docstring=dedent(doc), + f""" + {summary.strip()} + + .. deprecated:: {version} + {msg} + + {dedent(doc)}""" ) return wrapper diff --git a/pandas/util/_depr_module.py b/pandas/util/_depr_module.py index ae3c6359d20e0..99dafdd760d26 100644 --- a/pandas/util/_depr_module.py +++ b/pandas/util/_depr_module.py @@ -61,17 +61,15 @@ def __getattr__(self, name): if self.removals is not None and name in self.removals: warnings.warn( - "{deprmod}.{name} is deprecated and will be removed in " - "a future version.".format(deprmod=self.deprmod, name=name), + f"{self.deprmod}.{name} is deprecated and will be removed in " + "a future version.", FutureWarning, stacklevel=2, ) elif self.moved is not None and name in self.moved: warnings.warn( - "{deprmod} is deprecated and will be removed in " - "a future version.\nYou can access {name} as {moved}".format( - deprmod=self.deprmod, name=name, moved=self.moved[name] - ), + f"{self.deprmod} is deprecated and will be removed in " + f"a future version.\nYou can access {name} as {self.moved[name]}", FutureWarning, stacklevel=2, ) @@ -79,8 +77,8 @@ def __getattr__(self, name): deprmodto = self.deprmodto if deprmodto is False: warnings.warn( - "{deprmod}.{name} is deprecated and will be removed in " - "a future version.".format(deprmod=self.deprmod, name=name), + f"{self.deprmod}.{name} is deprecated and will be removed in " + "a future version.", FutureWarning, stacklevel=2, ) @@ -89,10 +87,8 @@ def __getattr__(self, name): deprmodto = obj.__module__ # The object is actually located in another module. warnings.warn( - "{deprmod}.{name} is deprecated. Please use " - "{deprmodto}.{name} instead.".format( - deprmod=self.deprmod, name=name, deprmodto=deprmodto - ), + f"{self.deprmod}.{name} is deprecated. Please use " + f"{deprmodto}.{name} instead.", FutureWarning, stacklevel=2, ) diff --git a/pandas/util/_doctools.py b/pandas/util/_doctools.py index 11156bc972857..91972fed7a3bb 100644 --- a/pandas/util/_doctools.py +++ b/pandas/util/_doctools.py @@ -113,7 +113,7 @@ def _insert_index(self, data): data.insert(0, "Index", data.index) else: for i in range(idx_nlevels): - data.insert(i, "Index{0}".format(i), data.index._get_level_values(i)) + data.insert(i, f"Index{i}", data.index._get_level_values(i)) col_nlevels = data.columns.nlevels if col_nlevels > 1: diff --git a/pandas/util/_print_versions.py b/pandas/util/_print_versions.py index d1c74e8530245..b9f7e0c69f8b6 100644 --- a/pandas/util/_print_versions.py +++ b/pandas/util/_print_versions.py @@ -40,14 +40,14 @@ def get_sys_info() -> List[Tuple[str, Optional[Union[str, int]]]]: [ ("python", ".".join(map(str, sys.version_info))), ("python-bits", struct.calcsize("P") * 8), - ("OS", "{sysname}".format(sysname=sysname)), - ("OS-release", "{release}".format(release=release)), + ("OS", f"{sysname}"), + ("OS-release", f"{release}"), # ("Version", "{version}".format(version=version)), - ("machine", "{machine}".format(machine=machine)), - ("processor", "{processor}".format(processor=processor)), - ("byteorder", "{byteorder}".format(byteorder=sys.byteorder)), - ("LC_ALL", "{lc}".format(lc=os.environ.get("LC_ALL", "None"))), - ("LANG", "{lang}".format(lang=os.environ.get("LANG", "None"))), + ("machine", f"{machine}"), + ("processor", f"{processor}"), + ("byteorder", f"{sys.byteorder}"), + ("LC_ALL", f"{os.environ.get('LC_ALL', 'None')}"), + ("LANG", f"{os.environ.get('LANG', 'None')}"), ("LOCALE", ".".join(map(str, locale.getlocale()))), ] ) diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py index 7669e729995d0..0e3ea25bf6fdb 100644 --- a/pandas/util/_test_decorators.py +++ b/pandas/util/_test_decorators.py @@ -129,7 +129,7 @@ def skip_if_installed(package: str) -> Callable: The name of the package. """ return pytest.mark.skipif( - safe_import(package), reason="Skipping because {} is installed.".format(package) + safe_import(package), reason=f"Skipping because {package} is installed." ) @@ -163,9 +163,9 @@ def skip_if_no(package: str, min_version: Optional[str] = None) -> Callable: a pytest.mark.skipif to use as either a test decorator or a parametrization mark. """ - msg = "Could not import '{}'".format(package) + msg = f"Could not import '{package}'" if min_version: - msg += " satisfying a min_version of {}".format(min_version) + msg += f" satisfying a min_version of {min_version}" return pytest.mark.skipif( not safe_import(package, min_version=min_version), reason=msg ) @@ -181,20 +181,17 @@ def skip_if_no(package: str, min_version: Optional[str] = None) -> Callable: is_platform_windows(), reason="not used on win32" ) skip_if_has_locale = pytest.mark.skipif( - _skip_if_has_locale(), - reason="Specific locale is set {lang}".format(lang=locale.getlocale()[0]), + _skip_if_has_locale(), reason=f"Specific locale is set {locale.getlocale()[0]}", ) skip_if_not_us_locale = pytest.mark.skipif( - _skip_if_not_us_locale(), - reason="Specific locale is set {lang}".format(lang=locale.getlocale()[0]), + _skip_if_not_us_locale(), reason=f"Specific locale is set {locale.getlocale()[0]}", ) skip_if_no_scipy = pytest.mark.skipif( _skip_if_no_scipy(), reason="Missing SciPy requirement" ) skip_if_no_ne = pytest.mark.skipif( not _USE_NUMEXPR, - reason="numexpr enabled->{enabled}, " - "installed->{installed}".format(enabled=_USE_NUMEXPR, installed=_NUMEXPR_INSTALLED), + reason=f"numexpr enabled->{_USE_NUMEXPR}, " f"installed->{_NUMEXPR_INSTALLED}", ) diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index 0eaf46d563163..cbfab83d0429c 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -26,13 +26,8 @@ def _check_arg_length(fname, args, max_fname_arg_count, compat_args): argument = "argument" if max_arg_count == 1 else "arguments" raise TypeError( - "{fname}() takes at most {max_arg} {argument} " - "({given_arg} given)".format( - fname=fname, - max_arg=max_arg_count, - argument=argument, - given_arg=actual_arg_count, - ) + f"{fname}() takes at most {max_arg_count} {argument} " + f"({actual_arg_count} given)" ) @@ -71,9 +66,9 @@ def _check_for_default_values(fname, arg_val_dict, compat_args): if not match: raise ValueError( ( - "the '{arg}' parameter is not " + f"the '{key}' parameter is not " "supported in the pandas " - "implementation of {fname}()".format(fname=fname, arg=key) + f"implementation of {fname}()" ) ) @@ -132,10 +127,7 @@ def _check_for_invalid_keys(fname, kwargs, compat_args): if diff: bad_arg = list(diff)[0] raise TypeError( - ( - "{fname}() got an unexpected " - "keyword argument '{arg}'".format(fname=fname, arg=bad_arg) - ) + (f"{fname}() got an unexpected " f"keyword argument '{bad_arg}'") ) @@ -223,8 +215,7 @@ def validate_args_and_kwargs(fname, args, kwargs, max_fname_arg_count, compat_ar for key in args_dict: if key in kwargs: raise TypeError( - "{fname}() got multiple values for keyword " - "argument '{arg}'".format(fname=fname, arg=key) + f"{fname}() got multiple values for keyword " f"argument '{key}'" ) kwargs.update(args_dict) @@ -235,8 +226,8 @@ def validate_bool_kwarg(value, arg_name): """ Ensures that argument passed in arg_name is of type bool. """ if not (is_bool(value) or value is None): raise ValueError( - 'For argument "{arg}" expected type bool, received ' - "type {typ}.".format(arg=arg_name, typ=type(value).__name__) + f'For argument "{arg_name}" expected type bool, received ' + f"type {type(value).__name__}." ) return value @@ -289,9 +280,7 @@ def validate_axis_style_args(data, args, kwargs, arg_name, method_name): # First fill with explicit values provided by the user... if arg_name in kwargs: if args: - msg = "{} got multiple values for argument '{}'".format( - method_name, arg_name - ) + msg = f"{method_name} got multiple values for argument '{arg_name}'" raise TypeError(msg) axis = data._get_axis_name(kwargs.get("axis", 0)) @@ -332,8 +321,8 @@ def validate_axis_style_args(data, args, kwargs, arg_name, method_name): out[data._AXIS_NAMES[0]] = args[0] out[data._AXIS_NAMES[1]] = args[1] else: - msg = "Cannot specify all of '{}', 'index', 'columns'." - raise TypeError(msg.format(arg_name)) + msg = f"Cannot specify all of '{arg_name}', 'index', 'columns'." + raise TypeError(msg) return out @@ -365,8 +354,8 @@ def validate_fillna_kwargs(value, method, validate_scalar_dict_value=True): elif value is not None and method is None: if validate_scalar_dict_value and isinstance(value, (list, tuple)): raise TypeError( - '"value" parameter must be a scalar or dict, but ' - 'you passed a "{0}"'.format(type(value).__name__) + f'"value" parameter must be a scalar or dict, but ' + 'you passed a "{type(value).__name__}"' ) elif value is not None and method is not None: From b9a91ee9859c2fc28580504b16e66bbe394dc291 Mon Sep 17 00:00:00 2001 From: Thomas Li Date: Thu, 12 Dec 2019 17:02:30 -0800 Subject: [PATCH 2/3] add files from pandas/io/formats --- pandas/io/formats/css.py | 13 +++++----- pandas/io/formats/excel.py | 19 +++++++------- pandas/io/formats/style.py | 51 ++++++++++++++------------------------ 3 files changed, 33 insertions(+), 50 deletions(-) diff --git a/pandas/io/formats/css.py b/pandas/io/formats/css.py index 6bc5f56bb5f7f..583dd49d4c66a 100644 --- a/pandas/io/formats/css.py +++ b/pandas/io/formats/css.py @@ -18,8 +18,7 @@ def expand(self, prop, value): mapping = self.SIDE_SHORTHANDS[len(tokens)] except KeyError: warnings.warn( - 'Could not expand "{prop}: {val}"'.format(prop=prop, val=value), - CSSWarning, + f'Could not expand "{prop}: {value}"', CSSWarning, ) return for key, idx in zip(self.SIDES, mapping): @@ -110,14 +109,14 @@ def __call__(self, declarations_str, inherited=None): # 3. TODO: resolve other font-relative units for side in self.SIDES: - prop = "border-{side}-width".format(side=side) + prop = f"border-{side}-width" if prop in props: props[prop] = self.size_to_pt( props[prop], em_pt=font_size, conversions=self.BORDER_WIDTH_RATIOS ) for prop in [ - "margin-{side}".format(side=side), - "padding-{side}".format(side=side), + f"margin-{side}", + f"padding-{side}", ]: if prop in props: # TODO: support % @@ -206,9 +205,9 @@ def _error(): val = round(val, 5) if int(val) == val: - size_fmt = "{fmt:d}pt".format(fmt=int(val)) + size_fmt = f"{int(val):d}pt" else: - size_fmt = "{fmt:f}pt".format(fmt=val) + size_fmt = f"{val:f}pt" return size_fmt def atomize(self, declarations): diff --git a/pandas/io/formats/excel.py b/pandas/io/formats/excel.py index 5d8573c1341f5..2f7a80eea1554 100644 --- a/pandas/io/formats/excel.py +++ b/pandas/io/formats/excel.py @@ -91,6 +91,7 @@ def build_xlstyle(self, props): "font": self.build_font(props), "number_format": self.build_number_format(props), } + # TODO: handle cell width and height: needs support in pandas.io.excel def remove_none(d): @@ -132,12 +133,10 @@ def build_border(self, props): return { side: { "style": self._border_style( - props.get("border-{side}-style".format(side=side)), - props.get("border-{side}-width".format(side=side)), - ), - "color": self.color_to_excel( - props.get("border-{side}-color".format(side=side)) + props.get(f"border-{side}-style"), + props.get(f"border-{side}-width"), ), + "color": self.color_to_excel(props.get(f"border-{side}-color")), } for side in ["top", "right", "bottom", "left"] } @@ -427,7 +426,7 @@ def _format_value(self, val): if missing.isposinf_scalar(val): val = self.inf_rep elif missing.isneginf_scalar(val): - val = "-{inf}".format(inf=self.inf_rep) + val = f"-{self.inf_rep}" elif self.float_format is not None: val = float(self.float_format % val) if getattr(val, "tzinfo", None) is not None: @@ -509,8 +508,8 @@ def _format_header_regular(self): if has_aliases: if len(self.header) != len(self.columns): raise ValueError( - "Writing {cols} cols but got {alias} " - "aliases".format(cols=len(self.columns), alias=len(self.header)) + f"Writing {len(self.columns)} cols but got {len(self.header)} " + "aliases" ) else: colnames = self.header @@ -718,8 +717,8 @@ def write( if num_rows > self.max_rows or num_cols > self.max_cols: raise ValueError( "This sheet is too large! Your sheet size is: " - + "{}, {} ".format(num_rows, num_cols) - + "Max sheet size is: {}, {}".format(self.max_rows, self.max_cols) + f"{num_rows}, {num_cols} " + f"Max sheet size is: {self.max_rows}, {self.max_cols}" ) if isinstance(writer, ExcelWriter): diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index a45045991e879..d3a12ccb77048 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -165,7 +165,7 @@ def default_display_func(x): if self.na_rep is not None and pd.isna(x): return self.na_rep elif is_float(x): - display_format = "{0:.{precision}f}".format(x, precision=self.precision) + display_format = f"{x:.{self.precision}f}" return display_format else: return x @@ -293,7 +293,7 @@ def format_attr(pair): name = self.data.columns.names[r] cs = [ BLANK_CLASS if name is None else INDEX_NAME_CLASS, - "level{lvl}".format(lvl=r), + f"level{r}", ] name = BLANK_VALUE if name is None else name row_es.append( @@ -310,8 +310,8 @@ def format_attr(pair): for c, value in enumerate(clabels[r]): cs = [ COL_HEADING_CLASS, - "level{lvl}".format(lvl=r), - "col{col}".format(col=c), + f"level{r}", + f"col{c}", ] cs.extend( cell_context.get("col_headings", {}).get(r, {}).get(c, []) @@ -339,7 +339,7 @@ def format_attr(pair): index_header_row = [] for c, name in enumerate(self.data.index.names): - cs = [INDEX_NAME_CLASS, "level{lvl}".format(lvl=c)] + cs = [INDEX_NAME_CLASS, f"level{c}"] name = "" if name is None else name index_header_row.append( {"type": "th", "value": name, "class": " ".join(cs)} @@ -358,8 +358,8 @@ def format_attr(pair): for c, value in enumerate(rlabels[r]): rid = [ ROW_HEADING_CLASS, - "level{lvl}".format(lvl=c), - "row{row}".format(row=r), + f"level{c}", + f"row{r}", ] es = { "type": "th", @@ -377,7 +377,7 @@ def format_attr(pair): row_es.append(es) for c, col in enumerate(self.data.columns): - cs = [DATA_CLASS, "row{row}".format(row=r), "col{col}".format(col=c)] + cs = [DATA_CLASS, f"row{r}", f"col{c}"] cs.extend(cell_context.get("data", {}).get(r, {}).get(c, [])) formatter = self._display_funcs[(r, c)] value = self.data.iloc[r, c] @@ -399,12 +399,7 @@ def format_attr(pair): props.append(x.split(":")) else: props.append(["", ""]) - cellstyle.append( - { - "props": props, - "selector": "row{row}_col{col}".format(row=r, col=c), - } - ) + cellstyle.append({"props": props, "selector": f"row{r}_col{c}"}) body.append(row_es) table_attr = self.table_attributes @@ -971,9 +966,7 @@ def hide_columns(self, subset): @staticmethod def _highlight_null(v, null_color): - return ( - "background-color: {color}".format(color=null_color) if pd.isna(v) else "" - ) + return f"background-color: {null_color}" if pd.isna(v) else "" def highlight_null(self, null_color="red"): """ @@ -1126,9 +1119,7 @@ def relative_luminance(rgba): def css(rgba): dark = relative_luminance(rgba) < text_color_threshold text_color = "#f1f1f1" if dark else "#000000" - return "background-color: {b};color: {c};".format( - b=colors.rgb2hex(rgba), c=text_color - ) + return f"background-color: {colors.rgb2hex(rgba)};color: {text_color};" if s.ndim == 1: return [css(rgba) for rgba in rgbas] @@ -1160,7 +1151,7 @@ def set_properties(self, subset=None, **kwargs): >>> df.style.set_properties(color="white", align="right") >>> df.style.set_properties(**{'background-color': 'yellow'}) """ - values = ";".join("{p}: {v}".format(p=p, v=v) for p, v in kwargs.items()) + values = ";".join(f"{p}: {v}" for p, v in kwargs.items()) f = lambda x: values return self.applymap(f, subset=subset) @@ -1191,12 +1182,9 @@ def css_bar(start, end, color): if end > start: css += "background: linear-gradient(90deg," if start > 0: - css += " transparent {s:.1f}%, {c} {s:.1f}%, ".format( - s=start, c=color - ) - css += "{c} {e:.1f}%, transparent {e:.1f}%)".format( - e=min(end, width), c=color - ) + css += f" transparent {start:.1f}%, {color} {start:.1f}%, " + e = min(end, width) + css += f"{color} {e:.1f}%, transparent {e:.1f}%)" return css def css(x): @@ -1358,7 +1346,7 @@ def _highlight_extrema(data, color="yellow", max_=True): """ Highlight the min or max in a Series or DataFrame. """ - attr = "background-color: {0}".format(color) + attr = f"background-color: {color}" if max_: extrema = data == np.nanmax(data.to_numpy()) @@ -1528,10 +1516,7 @@ def _maybe_wrap_formatter(formatter, na_rep: Optional[str]): elif callable(formatter): formatter_func = formatter else: - msg = ( - "Expected a template string or callable, got {formatter} " - "instead".format(formatter=formatter) - ) + msg = f"Expected a template string or callable, got {formatter} instead" raise TypeError(msg) if na_rep is None: @@ -1539,5 +1524,5 @@ def _maybe_wrap_formatter(formatter, na_rep: Optional[str]): elif isinstance(na_rep, str): return lambda x: na_rep if pd.isna(x) else formatter_func(x) else: - msg = "Expected a string, got {na_rep} instead".format(na_rep=na_rep) + msg = f"Expected a string, got {na_rep} instead" raise TypeError(msg) From 710916485da49b70145528de2438746fc23b5779 Mon Sep 17 00:00:00 2001 From: Thomas Li Date: Thu, 12 Dec 2019 20:02:20 -0800 Subject: [PATCH 3/3] Fix errors --- pandas/util/_tester.py | 2 +- pandas/util/_validators.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/util/_tester.py b/pandas/util/_tester.py index 7822ecdeeb4d8..6a3943cab692e 100644 --- a/pandas/util/_tester.py +++ b/pandas/util/_tester.py @@ -22,7 +22,7 @@ def test(extra_args=None): extra_args = [extra_args] cmd = extra_args cmd += [PKG] - print("running: pytest {}".format(" ".join(cmd))) + print(f"running: pytest {' '.join(cmd)}") sys.exit(pytest.main(cmd)) diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index cbfab83d0429c..8b675a6b688fe 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -354,8 +354,8 @@ def validate_fillna_kwargs(value, method, validate_scalar_dict_value=True): elif value is not None and method is None: if validate_scalar_dict_value and isinstance(value, (list, tuple)): raise TypeError( - f'"value" parameter must be a scalar or dict, but ' - 'you passed a "{type(value).__name__}"' + '"value" parameter must be a scalar or dict, but ' + f'you passed a "{type(value).__name__}"' ) elif value is not None and method is not None: