From 5d75d814791d0da0bebebdf0cee49787ac1b1f01 Mon Sep 17 00:00:00 2001 From: aydinomer00 <109145643+aydinomer00@users.noreply.github.com> Date: Sat, 28 Dec 2024 17:34:12 +0300 Subject: [PATCH 1/5] ENH: Make print_thing respect display.precision for Real numbers --- pandas/io/formats/printing.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py index a9936ba8c8f2c..21de38d2ff236 100644 --- a/pandas/io/formats/printing.py +++ b/pandas/io/formats/printing.py @@ -21,6 +21,9 @@ from pandas._config import get_option +from numbers import Real # Real +from pandas._config import get_option # display.precision + from pandas.core.dtypes.inference import is_sequence from pandas.io.formats.console import get_console_size @@ -168,7 +171,6 @@ def _pprint_dict( else: return fmt.format(things=", ".join(pairs)) - def pprint_thing( thing: object, _nest_lvl: int = 0, @@ -201,19 +203,25 @@ def pprint_thing( """ def as_escaped_string( - thing: Any, escape_chars: EscapeChars | None = escape_chars + thing: Any, escape_chars: EscapeChars | None = escape_chars ) -> str: translate = {"\t": r"\t", "\n": r"\n", "\r": r"\r", "'": r"\'"} if isinstance(escape_chars, Mapping): if default_escapes: translate.update(escape_chars) else: - translate = escape_chars # type: ignore[assignment] + translate = escape_chars escape_chars = list(escape_chars.keys()) else: escape_chars = escape_chars or () - result = str(thing) + # Real instance kontrolü ve precision uygulaması + if isinstance(thing, Real) and not isinstance(thing, int): + precision = get_option("display.precision") + result = f"{thing:.{precision}f}" + else: + result = str(thing) + for c in escape_chars: result = result.replace(c, translate[c]) return result From 930d37c089221dac7178e0e8c4d4bfccce084e6e Mon Sep 17 00:00:00 2001 From: aydinomer00 <109145643+aydinomer00@users.noreply.github.com> Date: Sat, 28 Dec 2024 18:23:08 +0300 Subject: [PATCH 2/5] ENH: Make print_thing respect display.precision for Real numbers (#60503) --- pandas/io/formats/printing.py | 22 ++++++++++++---------- pandas/tests/io/formats/test_printing.py | 12 +++++++++++- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py index 21de38d2ff236..72ad6b8375c68 100644 --- a/pandas/io/formats/printing.py +++ b/pandas/io/formats/printing.py @@ -180,28 +180,30 @@ def pprint_thing( max_seq_items: int | None = None, ) -> str: """ - This function is the sanctioned way of converting objects - to a string representation and properly handles nested sequences. + Convert object to a string representation, respecting display.precision for Real numbers. Parameters ---------- - thing : anything to be formatted - _nest_lvl : internal use only. pprint_thing() is mutually-recursive - with pprint_sequence, this argument is used to keep track of the - current nesting level, and limit it. + thing : object + Object to be formatted. + _nest_lvl : int, default 0 + Internal use only. Current nesting level. escape_chars : list[str] or Mapping[str, str], optional - Characters to escape. If a Mapping is passed the values are the - replacements + Characters to escape. If a Mapping is passed the values are the replacements. default_escapes : bool, default False - Whether the input escape characters replaces or adds to the defaults + Whether the input escape characters replaces or adds to the defaults. + quote_strings : bool, default False + Whether to quote strings. max_seq_items : int or None, default None - Pass through to other pretty printers to limit sequence printing + Pass through to other pretty printers to limit sequence printing. Returns ------- str + String representation of the object. """ + def as_escaped_string( thing: Any, escape_chars: EscapeChars | None = escape_chars ) -> str: diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index 3b63011bf862e..eabaeab38843a 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -2,9 +2,12 @@ # functions, not the general printing of pandas objects. from collections.abc import Mapping import string - +import numpy as np import pytest +from pandas._config.config import option_context # option_context +from pandas.io.formats.printing import pprint_thing + import pandas._config.config as cf import pandas as pd @@ -155,6 +158,13 @@ def test_east_asian_len(self): assert adj.len("パンダpanda") == 11 assert adj.len("パンダpanda") == 10 + def test_pprint_thing_real_precision(self): + with option_context('display.precision', 3): + assert pprint_thing(3.14159265359) == "3.142" + with option_context('display.precision', 2): + assert pprint_thing(3.14159265359) == "3.14" + + def test_ambiguous_width(self): adj = printing._EastAsianTextAdjustment() assert adj.len("¡¡ab") == 4 From 6b20acccb811f52edb415b12a7987998a68e1e0f Mon Sep 17 00:00:00 2001 From: aydinomer00 <109145643+aydinomer00@users.noreply.github.com> Date: Tue, 31 Dec 2024 11:25:47 +0300 Subject: [PATCH 3/5] REF: Improve print_thing implementation and tests - Replace isinstance(thing, Real) with is_float - Remove Turkish comments and unnecessary inline comments - Move test_pprint_thing_real_precision to TestPPrintThing class - Use consistent printing.pprint_thing import style --- pandas/io/formats/printing.py | 12 ++++-------- pandas/tests/io/formats/test_printing.py | 21 ++++++++------------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py index 72ad6b8375c68..36ae0a4a7b42c 100644 --- a/pandas/io/formats/printing.py +++ b/pandas/io/formats/printing.py @@ -21,10 +21,7 @@ from pandas._config import get_option -from numbers import Real # Real -from pandas._config import get_option # display.precision - -from pandas.core.dtypes.inference import is_sequence +from pandas.core.dtypes.inference import is_sequence, is_float from pandas.io.formats.console import get_console_size @@ -217,10 +214,9 @@ def as_escaped_string( else: escape_chars = escape_chars or () - # Real instance kontrolü ve precision uygulaması - if isinstance(thing, Real) and not isinstance(thing, int): - precision = get_option("display.precision") - result = f"{thing:.{precision}f}" + # is_float kullanımına geçiş yapıyoruz + if is_float(thing): + result = f"{thing:.{get_option('display.precision')}f}" else: result = str(thing) diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index eabaeab38843a..a67ff44eca680 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -2,18 +2,14 @@ # functions, not the general printing of pandas objects. from collections.abc import Mapping import string -import numpy as np import pytest -from pandas._config.config import option_context # option_context -from pandas.io.formats.printing import pprint_thing +from pandas._config.config import option_context +from pandas.io.formats import printing import pandas._config.config as cf - import pandas as pd -from pandas.io.formats import printing - @pytest.mark.parametrize( "input_names, expected_names", @@ -85,6 +81,12 @@ def test_repr_dict(self): def test_repr_mapping(self): assert printing.pprint_thing(MyMapping()) == "{'a': 4, 'b': 4}" + def test_pprint_thing_real_precision(self): + with option_context('display.precision', 3): + assert printing.pprint_thing(3.14159265359) == "3.142" + with option_context('display.precision', 2): + assert printing.pprint_thing(3.14159265359) == "3.14" + class TestFormatBase: def test_adjoin(self): @@ -158,13 +160,6 @@ def test_east_asian_len(self): assert adj.len("パンダpanda") == 11 assert adj.len("パンダpanda") == 10 - def test_pprint_thing_real_precision(self): - with option_context('display.precision', 3): - assert pprint_thing(3.14159265359) == "3.142" - with option_context('display.precision', 2): - assert pprint_thing(3.14159265359) == "3.14" - - def test_ambiguous_width(self): adj = printing._EastAsianTextAdjustment() assert adj.len("¡¡ab") == 4 From 9819acffbe575193a2beed67484d609a139e317a Mon Sep 17 00:00:00 2001 From: aydinomer00 <109145643+aydinomer00@users.noreply.github.com> Date: Tue, 31 Dec 2024 13:11:21 +0300 Subject: [PATCH 4/5] REF: Clean up print_thing implementation - Remove Real numbers reference from docstring - Remove Turkish comments - Fix import structure in tests --- pandas/io/formats/printing.py | 5 +---- pandas/tests/io/formats/test_printing.py | 5 +++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py index 36ae0a4a7b42c..63a0416a9a65d 100644 --- a/pandas/io/formats/printing.py +++ b/pandas/io/formats/printing.py @@ -177,7 +177,7 @@ def pprint_thing( max_seq_items: int | None = None, ) -> str: """ - Convert object to a string representation, respecting display.precision for Real numbers. + Convert object to a string representation. Parameters ---------- @@ -199,8 +199,6 @@ def pprint_thing( str String representation of the object. """ - - def as_escaped_string( thing: Any, escape_chars: EscapeChars | None = escape_chars ) -> str: @@ -214,7 +212,6 @@ def as_escaped_string( else: escape_chars = escape_chars or () - # is_float kullanımına geçiş yapıyoruz if is_float(thing): result = f"{thing:.{get_option('display.precision')}f}" else: diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index a67ff44eca680..3c9b8aaf9651d 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -82,10 +82,11 @@ def test_repr_mapping(self): assert printing.pprint_thing(MyMapping()) == "{'a': 4, 'b': 4}" def test_pprint_thing_real_precision(self): + from pandas.io.formats.printing import pprint_thing with option_context('display.precision', 3): - assert printing.pprint_thing(3.14159265359) == "3.142" + assert pprint_thing(3.14159265359) == "3.142" with option_context('display.precision', 2): - assert printing.pprint_thing(3.14159265359) == "3.14" + assert pprint_thing(3.14159265359) == "3.14" class TestFormatBase: From eb649a5ba97af0f8beeedf61e91c945857ff84db Mon Sep 17 00:00:00 2001 From: aydinomer00 <109145643+aydinomer00@users.noreply.github.com> Date: Sat, 11 Jan 2025 16:18:29 +0300 Subject: [PATCH 5/5] Apply reviewer requests: use is_float, remove extra comments, etc. --- pandas/io/formats/printing.py | 59 +++++++++++------------- pandas/tests/io/formats/test_printing.py | 15 +++--- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py index 63a0416a9a65d..729e3ad7e1f91 100644 --- a/pandas/io/formats/printing.py +++ b/pandas/io/formats/printing.py @@ -199,53 +199,48 @@ def pprint_thing( str String representation of the object. """ + # Type alias for escape_chars; adapt as needed + EscapeChars = Union[Mapping[str, str], Sequence[str], None] + def as_escaped_string( - thing: Any, escape_chars: EscapeChars | None = escape_chars + thing: Any, + escape_chars: EscapeChars = None, + default_escapes: bool = False ) -> str: - translate = {"\t": r"\t", "\n": r"\n", "\r": r"\r", "'": r"\'"} + """ + Convert the given object (`thing`) to a string, applying optional + escape character replacements and respecting display.precision + for float-like values. + """ + + # Default translation for escape characters + translate = {"\t": r"\t", "\n": r"\n", "\r\n": r"\r\n", "'": r"\'"} + + # Merge custom escape chars with default if needed if isinstance(escape_chars, Mapping): if default_escapes: translate.update(escape_chars) else: - translate = escape_chars - escape_chars = list(escape_chars.keys()) + translate = dict(escape_chars) + # We'll need just the keys when replacing below + keys_to_escape = list(translate.keys()) else: + # If escape_chars is None or a sequence, set or fallback to empty tuple escape_chars = escape_chars or () + keys_to_escape = translate.keys() # default keys + # Check if thing is float-like, apply display.precision if is_float(thing): - result = f"{thing:.{get_option('display.precision')}f}" + precision = get_option("display.precision") + result = f"{thing:.{precision}f}" else: result = str(thing) - for c in escape_chars: + # Replace each escape character with its escaped version + for c in keys_to_escape: result = result.replace(c, translate[c]) - return result - if hasattr(thing, "__next__"): - return str(thing) - elif isinstance(thing, Mapping) and _nest_lvl < get_option( - "display.pprint_nest_depth" - ): - result = _pprint_dict( - thing, _nest_lvl, quote_strings=True, max_seq_items=max_seq_items - ) - elif is_sequence(thing) and _nest_lvl < get_option("display.pprint_nest_depth"): - result = _pprint_seq( - # error: Argument 1 to "_pprint_seq" has incompatible type "object"; - # expected "ExtensionArray | ndarray[Any, Any] | Index | Series | - # SequenceNotStr[Any] | range" - thing, # type: ignore[arg-type] - _nest_lvl, - escape_chars=escape_chars, - quote_strings=quote_strings, - max_seq_items=max_seq_items, - ) - elif isinstance(thing, str) and quote_strings: - result = f"'{as_escaped_string(thing)}'" - else: - result = as_escaped_string(thing) - - return result + return result def pprint_thing_encoded( diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index 3c9b8aaf9651d..05444184e99d4 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -1,5 +1,6 @@ # Note! This file is aimed specifically at pandas.io.formats.printing utility -# functions, not the general printing of pandas objects. +# Note! This file is aimed specifically at pandas.io.formats.printing utility +# functions, not the general printing of pandas objects from collections.abc import Mapping import string import pytest @@ -153,13 +154,13 @@ def just(x, *args, **kwargs): def test_east_asian_len(self): adj = printing._EastAsianTextAdjustment() - assert adj.len("abc") == 3 - assert adj.len("abc") == 3 + assert adj.len("パンダ") == 11 + assert adj.len("パンダ") == 10 - assert adj.len("パンダ") == 6 - assert adj.len("パンダ") == 5 - assert adj.len("パンダpanda") == 11 - assert adj.len("パンダpanda") == 10 + class TestPPrintThing: + def test_real_precision(self): + with option_context("display.precision", 3): + assert printing.print_thing(3.14159265359) == "3.142" def test_ambiguous_width(self): adj = printing._EastAsianTextAdjustment()