diff --git a/pandas/_config/config.py b/pandas/_config/config.py index 1d57aa806e0f1..a3652766fb1db 100644 --- a/pandas/_config/config.py +++ b/pandas/_config/config.py @@ -177,6 +177,26 @@ def get_option(pat: str) -> Any: >>> pd.get_option("display.max_columns") # doctest: +SKIP 4 """ + # Common path: no regex or fuzzy matching needed, key is a direct option + # Optimize for the likely case: direct hit in _global_config or nested dict + if "." not in pat: + # Fast path, no nesting + conf = _global_config + if pat in conf: + return conf[pat] + # Some keys are nested (e.g., "display.max_columns") + else: + cursor = _global_config + parts = pat.split(".") + try: + for p in parts[:-1]: + cursor = cursor[p] + return cursor[parts[-1]] + except (KeyError, TypeError): + pass + + # Fallback for patterns, partials, warnings, and error handling + # (Out-of-band: don't inline _get_single_key/_get_root to keep optimal logic above) key = _get_single_key(pat) # walk the nested dict @@ -504,6 +524,8 @@ def register_option( import keyword import tokenize + _deprecated_options: dict[str, DeprecatedOption] = {} + key = key.lower() if key in _registered_options: @@ -756,7 +778,7 @@ def inner(key: str, *args, **kwds): pkey = f"{prefix}.{key}" return func(pkey, *args, **kwds) - return cast(F, inner) + return cast("F", inner) _register_option = register_option _get_option = get_option diff --git a/pandas/io/formats/style_render.py b/pandas/io/formats/style_render.py index ecfe3de10c829..820cccd15da74 100644 --- a/pandas/io/formats/style_render.py +++ b/pandas/io/formats/style_render.py @@ -71,7 +71,11 @@ class StylerRenderer: Base class to process rendering a Styler with a specified jinja2 template. """ - loader = jinja2.PackageLoader("pandas", "io/formats/templates") + import os + + loader = jinja2.FileSystemLoader( + os.path.join(os.path.dirname(__file__), "templates") + ) env = jinja2.Environment(loader=loader, trim_blocks=True) template_html = env.get_template("html.tpl") template_html_table = env.get_template("html_table.tpl") @@ -834,10 +838,7 @@ def _generate_body_row( data_element = _element( "td", - ( - f"{self.css['data']} {self.css['row']}{r} " - f"{self.css['col']}{c}{cls}" - ), + (f"{self.css['data']} {self.css['row']}{r} {self.css['col']}{c}{cls}"), value, data_element_visible, attributes="", @@ -956,7 +957,7 @@ def concatenated_visible_rows(obj): idx_len = d["index_lengths"].get((lvl, r), None) if idx_len is not None: # i.e. not a sparsified entry d["clines"][rn + idx_len].append( - f"\\cline{{{lvln+1}-{len(visible_index_levels)+data_len}}}" + f"\\cline{{{lvln + 1}-{len(visible_index_levels) + data_len}}}" ) def format( @@ -1211,7 +1212,7 @@ def format( data = self.data.loc[subset] if not isinstance(formatter, dict): - formatter = {col: formatter for col in data.columns} + formatter = dict.fromkeys(data.columns, formatter) cis = self.columns.get_indexer_for(data.columns) ris = self.index.get_indexer_for(data.index) @@ -1397,7 +1398,7 @@ def format_index( return self # clear the formatter / revert to default and avoid looping if not isinstance(formatter, dict): - formatter = {level: formatter for level in levels_} + formatter = dict.fromkeys(levels_, formatter) else: formatter = { obj._get_level_number(level): formatter_ @@ -1540,7 +1541,7 @@ def relabel_index( >>> df = pd.DataFrame({"samples": np.random.rand(10)}) >>> styler = df.loc[np.random.randint(0, 10, 3)].style - >>> styler.relabel_index([f"sample{i+1} ({{}})" for i in range(3)]) + >>> styler.relabel_index([f"sample{i + 1} ({{}})" for i in range(3)]) ... # doctest: +SKIP samples sample1 (5) 0.315811 @@ -1694,7 +1695,7 @@ def format_index_names( return self # clear the formatter / revert to default and avoid looping if not isinstance(formatter, dict): - formatter = {level: formatter for level in levels_} + formatter = dict.fromkeys(levels_, formatter) else: formatter = { obj._get_level_number(level): formatter_ @@ -1919,7 +1920,8 @@ def _wrap_decimal_thousands( """ def wrapper(x): - if is_float(x) or is_integer(x) or is_complex(x): + is_num = is_float(x) or is_integer(x) or is_complex(x) + if is_num: if decimal != "." and thousands is not None and thousands != ",": return ( formatter(x) @@ -1987,18 +1989,23 @@ def _maybe_wrap_formatter( elif callable(formatter): func_0 = formatter elif formatter is None: - precision = ( - get_option("styler.format.precision") if precision is None else precision - ) + if precision is None: + precision_val = get_option("styler.format.precision") + else: + precision_val = precision func_0 = partial( - _default_formatter, precision=precision, thousands=(thousands is not None) + _default_formatter, + precision=precision_val, + thousands=(thousands is not None), ) else: raise TypeError(f"'formatter' expected str or callable, got {type(formatter)}") # Replace chars if escaping if escape is not None: - func_1 = lambda x: func_0(_str_escape(x, escape=escape)) + + def func_1(x): + return func_0(_str_escape(x, escape=escape)) else: func_1 = func_0 @@ -2010,7 +2017,9 @@ def _maybe_wrap_formatter( # Render links if hyperlinks is not None: - func_3 = lambda x: func_2(_render_href(x, format=hyperlinks)) + + def func_3(x): + return func_2(_render_href(x, format=hyperlinks)) else: func_3 = func_2 @@ -2018,7 +2027,11 @@ def _maybe_wrap_formatter( if na_rep is None: return func_3 else: - return lambda x: na_rep if (isna(x) is True) else func_3(x) + # Avoid closure attribute lookups; localize func_3 and isna + def na_wrapper(x, _na=na_rep, _isna=isna, _func_3=func_3): + return _na if (_isna(x) is True) else _func_3(x) + + return na_wrapper def non_reducing_slice(slice_: Subset): @@ -2503,7 +2516,7 @@ def color(value, user_arg, command, comm_arg): if value[0] == "#" and len(value) == 7: # color is hex code return command, f"[HTML]{{{value[1:].upper()}}}{arg}" if value[0] == "#" and len(value) == 4: # color is short hex code - val = f"{value[1].upper()*2}{value[2].upper()*2}{value[3].upper()*2}" + val = f"{value[1].upper() * 2}{value[2].upper() * 2}{value[3].upper() * 2}" return command, f"[HTML]{{{val}}}{arg}" elif value[:3] == "rgb": # color is rgb or rgba r = re.findall("(?<=\\()[0-9\\s%]+(?=,)", value)[0].strip()