From 42203a9228c81a502e96f14253791f5cf79343e3 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Fri, 8 Nov 2024 17:37:30 +0200 Subject: [PATCH 01/14] remove single quotes in index names when printing --- pandas/core/indexes/frozen.py | 2 +- pandas/io/formats/printing.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pandas/core/indexes/frozen.py b/pandas/core/indexes/frozen.py index c559c529586b5..0ba1c9a59872e 100644 --- a/pandas/core/indexes/frozen.py +++ b/pandas/core/indexes/frozen.py @@ -110,7 +110,7 @@ def _disabled(self, *args, **kwargs) -> NoReturn: raise TypeError(f"'{type(self).__name__}' does not support mutable operations.") def __str__(self) -> str: - return pprint_thing(self, quote_strings=True, escape_chars=("\t", "\r", "\n")) + return pprint_thing(self, quote_strings=True, escape_chars=("\t", "\r", "\n","'")) def __repr__(self) -> str: return f"{type(self).__name__}({self!s})" diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py index 67b5eb6f5ee5b..caf8928865613 100644 --- a/pandas/io/formats/printing.py +++ b/pandas/io/formats/printing.py @@ -199,18 +199,17 @@ def pprint_thing( ------- str """ - def as_escaped_string( thing: Any, escape_chars: EscapeChars | None = escape_chars ) -> str: - translate = {"\t": r"\t", "\n": r"\n", "\r": r"\r"} + translate = {"\t": r"\t", "\n": r"\n", "\r": r"\r", "'": ""} if isinstance(escape_chars, Mapping): if default_escapes: translate.update(escape_chars) else: translate = escape_chars # type: ignore[assignment] escape_chars = list(escape_chars.keys()) - else: + else: escape_chars = escape_chars or () result = str(thing) From 5d9edbfc736af9abc38710a76d06daf538551be7 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Fri, 8 Nov 2024 21:41:33 +0200 Subject: [PATCH 02/14] Removed trailing whitespace --- pandas/io/formats/printing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py index caf8928865613..b9217ec9623a0 100644 --- a/pandas/io/formats/printing.py +++ b/pandas/io/formats/printing.py @@ -209,7 +209,7 @@ def as_escaped_string( else: translate = escape_chars # type: ignore[assignment] escape_chars = list(escape_chars.keys()) - else: + else: escape_chars = escape_chars or () result = str(thing) From 5da2343c706c7225815ee5c5b441a135f7ad55f1 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Fri, 8 Nov 2024 21:51:52 +0200 Subject: [PATCH 03/14] Removed trailing whitespaces --- pandas/core/indexes/frozen.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pandas/core/indexes/frozen.py b/pandas/core/indexes/frozen.py index 0ba1c9a59872e..7086c1f0c4081 100644 --- a/pandas/core/indexes/frozen.py +++ b/pandas/core/indexes/frozen.py @@ -110,7 +110,11 @@ def _disabled(self, *args, **kwargs) -> NoReturn: raise TypeError(f"'{type(self).__name__}' does not support mutable operations.") def __str__(self) -> str: - return pprint_thing(self, quote_strings=True, escape_chars=("\t", "\r", "\n","'")) + return pprint_thing( + self, + quote_strings=True, + escape_chars=("\t", "\r", "\n", "'") + ) def __repr__(self) -> str: return f"{type(self).__name__}({self!s})" From f0a90088830346185c166c3adee92081349b9f13 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Sat, 9 Nov 2024 11:39:06 +0200 Subject: [PATCH 04/14] Added relevant tests when removing single quotes --- pandas/tests/io/formats/test_printing.py | 25 ++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index 1009dfec53218..35e1fa64a64b9 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -2,12 +2,33 @@ # functions, not the general printing of pandas objects. from collections.abc import Mapping import string - +import ast import pandas._config.config as cf - +import pandas as pd from pandas.io.formats import printing +def test_formatted_index_names(): + # Test cases: (input index names, expected formatted index names as lists) + test_cases = [ + (["'a", "b"], ['a', 'b']), # Remove leading quote + (["test's", "b"], ['tests', 'b']), # Remove apostrophe + (["'test'", "b"], ['test', 'b']), # Remove surrounding quotes + (["test","'b"], ["test",'b']), # Remove single quote + (["'test\n'", "b"], ['test\n', 'b']) # Remove quotes, preserve newline + ] + + for input_names, expected_names in test_cases: + # Create DataFrame with specified index names + df = pd.DataFrame({name: [1, 2, 3] for name in input_names}).set_index(input_names) + index_names_str = df.index.names.__str__() + + formatted_names = ast.literal_eval(index_names_str) + + # Compare the formatted names with the expected names + assert formatted_names == expected_names + + def test_adjoin(): data = [["a", "b", "c"], ["dd", "ee", "ff"], ["ggg", "hhh", "iii"]] expected = "a dd ggg\nb ee hhh\nc ff iii" From 9552a4394cda7909ff424ccfd3a6df31010d0482 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Sat, 9 Nov 2024 12:21:32 +0200 Subject: [PATCH 05/14] Refactor test_formatted_index_names to adhere with line-legth constraints --- pandas/tests/io/formats/test_printing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index 35e1fa64a64b9..5b48da8420376 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -20,7 +20,9 @@ def test_formatted_index_names(): for input_names, expected_names in test_cases: # Create DataFrame with specified index names - df = pd.DataFrame({name: [1, 2, 3] for name in input_names}).set_index(input_names) + df = pd.DataFrame( + {name: [1, 2, 3] for name in input_names} + ).set_index(input_names) index_names_str = df.index.names.__str__() formatted_names = ast.literal_eval(index_names_str) From 2fa7eeb2c450a63ef18dc0e823b4feefeb009c3f Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Sun, 10 Nov 2024 17:31:20 +0200 Subject: [PATCH 06/14] Escape single quotes --- pandas/io/formats/printing.py | 2 +- pandas/tests/io/formats/test_printing.py | 36 ++++++++++-------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py index b9217ec9623a0..0b1b97dc8c045 100644 --- a/pandas/io/formats/printing.py +++ b/pandas/io/formats/printing.py @@ -202,7 +202,7 @@ def pprint_thing( def as_escaped_string( thing: Any, escape_chars: EscapeChars | None = escape_chars ) -> str: - translate = {"\t": r"\t", "\n": r"\n", "\r": r"\r", "'": ""} + translate = {"\t": r"\t", "\n": r"\n", "\r": r"\r", "'": r"\'"} if isinstance(escape_chars, Mapping): if default_escapes: translate.update(escape_chars) diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index 5b48da8420376..ba856e3600b72 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -2,33 +2,27 @@ # functions, not the general printing of pandas objects. from collections.abc import Mapping import string -import ast +import pytest import pandas._config.config as cf import pandas as pd from pandas.io.formats import printing -def test_formatted_index_names(): - # Test cases: (input index names, expected formatted index names as lists) - test_cases = [ - (["'a", "b"], ['a', 'b']), # Remove leading quote - (["test's", "b"], ['tests', 'b']), # Remove apostrophe - (["'test'", "b"], ['test', 'b']), # Remove surrounding quotes - (["test","'b"], ["test",'b']), # Remove single quote - (["'test\n'", "b"], ['test\n', 'b']) # Remove quotes, preserve newline - ] - - for input_names, expected_names in test_cases: - # Create DataFrame with specified index names - df = pd.DataFrame( - {name: [1, 2, 3] for name in input_names} +@pytest.mark.parametrize("input_names, expected_names", [ + (["'a", "b"], ["\'a", "b"]), # Escape leading quote + (["test's", "b"], ["test\'s", "b"]), # Escape apostrophe + (["'test'", "b"], ["\'test\'", "b"]), # Escape surrounding quotes + (["test","b'"], ["test","b\'"]), # Escape single quote + (["'test\n'", "b"], ["\'test\n\'", "b"]) # Escape and preserve newline +]) +def test_formatted_index_names(input_names, expected_names): + # Create DataFrame with specified index names + df = pd.DataFrame( + {name: [1, 2, 3] for name in input_names} ).set_index(input_names) - index_names_str = df.index.names.__str__() - - formatted_names = ast.literal_eval(index_names_str) - - # Compare the formatted names with the expected names - assert formatted_names == expected_names + formatted_names = df.index.names + + assert formatted_names == expected_names def test_adjoin(): From bdcbca13507a4b97dc8978d77466716fda250adb Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Tue, 12 Nov 2024 09:48:47 +0200 Subject: [PATCH 07/14] Apply formatting and import sorting from pre-commit hooks --- pandas/io/formats/printing.py | 1 + pandas/tests/io/formats/test_printing.py | 29 ++++++++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py index 0b1b97dc8c045..a9936ba8c8f2c 100644 --- a/pandas/io/formats/printing.py +++ b/pandas/io/formats/printing.py @@ -199,6 +199,7 @@ def pprint_thing( ------- str """ + 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 ba856e3600b72..01e16b4228bf4 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -2,26 +2,31 @@ # functions, not the general printing of pandas objects. from collections.abc import Mapping import string + import pytest + import pandas._config.config as cf + import pandas as pd + from pandas.io.formats import printing -@pytest.mark.parametrize("input_names, expected_names", [ - (["'a", "b"], ["\'a", "b"]), # Escape leading quote - (["test's", "b"], ["test\'s", "b"]), # Escape apostrophe - (["'test'", "b"], ["\'test\'", "b"]), # Escape surrounding quotes - (["test","b'"], ["test","b\'"]), # Escape single quote - (["'test\n'", "b"], ["\'test\n\'", "b"]) # Escape and preserve newline -]) +@pytest.mark.parametrize( + "input_names, expected_names", + [ + (["'a", "b"], ["'a", "b"]), # Escape leading quote + (["test's", "b"], ["test's", "b"]), # Escape apostrophe + (["'test'", "b"], ["'test'", "b"]), # Escape surrounding quotes + (["test", "b'"], ["test", "b'"]), # Escape single quote + (["'test\n'", "b"], ["'test\n'", "b"]), # Escape and preserve newline + ], +) def test_formatted_index_names(input_names, expected_names): - # Create DataFrame with specified index names - df = pd.DataFrame( - {name: [1, 2, 3] for name in input_names} - ).set_index(input_names) + # GH#60190 + df = pd.DataFrame({name: [1, 2, 3] for name in input_names}).set_index(input_names) formatted_names = df.index.names - + assert formatted_names == expected_names From a6cad8db92a4a7d5fdd63f84b4ce103aa679c47f Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Tue, 12 Nov 2024 09:56:56 +0200 Subject: [PATCH 08/14] Apply formatting and import sorting from pre-commit hooks --- doc/source/whatsnew/v3.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index de69166b8c196..f987e0030babb 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -665,7 +665,7 @@ Indexing ^^^^^^^^ - Bug in :meth:`DataFrame.__getitem__` returning modified columns when called with ``slice`` in Python 3.12 (:issue:`57500`) - Bug in :meth:`DataFrame.from_records` throwing a ``ValueError`` when passed an empty list in ``index`` (:issue:`58594`) -- +- Bug in :func:`pprint_thing` with ``quote_strings=True`` failing for strings with embedded single quotes (:issue:`60190`) Missing ^^^^^^^ From 9d02418a7bd78e468a40b899716f92153e694d94 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Tue, 12 Nov 2024 09:57:55 +0200 Subject: [PATCH 09/14] Apply formatting and import sorting from pre-commit hooks --- doc/source/whatsnew/v3.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index f987e0030babb..01bfacf5bcad9 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -663,9 +663,9 @@ Interval Indexing ^^^^^^^^ +- Bug in :func:`pprint_thing` with ``quote_strings=True`` failing for strings with embedded single quotes (:issue:`60190`) - Bug in :meth:`DataFrame.__getitem__` returning modified columns when called with ``slice`` in Python 3.12 (:issue:`57500`) - Bug in :meth:`DataFrame.from_records` throwing a ``ValueError`` when passed an empty list in ``index`` (:issue:`58594`) -- Bug in :func:`pprint_thing` with ``quote_strings=True`` failing for strings with embedded single quotes (:issue:`60190`) Missing ^^^^^^^ From 67fd773a1d0164e8dc4c97fda93c0d12959dd050 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Tue, 12 Nov 2024 10:14:11 +0200 Subject: [PATCH 10/14] Apply formatting and import sorting from pre-commit hooks --- pandas/core/indexes/frozen.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pandas/core/indexes/frozen.py b/pandas/core/indexes/frozen.py index 7086c1f0c4081..254bd71ade209 100644 --- a/pandas/core/indexes/frozen.py +++ b/pandas/core/indexes/frozen.py @@ -111,9 +111,7 @@ def _disabled(self, *args, **kwargs) -> NoReturn: def __str__(self) -> str: return pprint_thing( - self, - quote_strings=True, - escape_chars=("\t", "\r", "\n", "'") + self, quote_strings=True, escape_chars=("\t", "\r", "\n", "'") ) def __repr__(self) -> str: From 8c41d9deed992876cfd39e0d629c3e1cf6f47313 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Sun, 17 Nov 2024 15:34:23 +0200 Subject: [PATCH 11/14] Update whatsnew --- doc/source/whatsnew/v3.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 88740721de435..2bccf005994f1 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -663,7 +663,7 @@ Interval Indexing ^^^^^^^^ -- Bug in :func:`pprint_thing` with ``quote_strings=True`` failing for strings with embedded single quotes (:issue:`60190`) +- Bug in :class:`Index` printed names do not escape single quotes (:issue:`60190`) - Bug in :meth:`DataFrame.__getitem__` returning modified columns when called with ``slice`` in Python 3.12 (:issue:`57500`) - Bug in :meth:`DataFrame.from_records` throwing a ``ValueError`` when passed an empty list in ``index`` (:issue:`58594`) From 2c3625a6e60ccbff2d751c421bfb8ddf3c289623 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Fri, 22 Nov 2024 10:06:45 +0200 Subject: [PATCH 12/14] Update whatsnew in v3.0.0. --- doc/source/whatsnew/v3.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index e5458a6383ae9..048e024e63a8f 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -665,7 +665,7 @@ Interval Indexing ^^^^^^^^ -- Bug in :class:`Index` printed names do not escape single quotes (:issue:`60190`) +- Bug in printing :attr:`Index.names` and :attr:`MultiIndex.levels` would not escape single quotes (:issue:`60190`) - Bug in :meth:`DataFrame.__getitem__` returning modified columns when called with ``slice`` in Python 3.12 (:issue:`57500`) - Bug in :meth:`DataFrame.from_records` throwing a ``ValueError`` when passed an empty list in ``index`` (:issue:`58594`) From 6391b7636ab348b8ee3275790edfec05ff083e78 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Fri, 22 Nov 2024 10:07:51 +0200 Subject: [PATCH 13/14] Update whatsnew in v3.0.0. --- doc/source/whatsnew/v3.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 048e024e63a8f..f4a428ddca60a 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -665,9 +665,9 @@ Interval Indexing ^^^^^^^^ -- Bug in printing :attr:`Index.names` and :attr:`MultiIndex.levels` would not escape single quotes (:issue:`60190`) - Bug in :meth:`DataFrame.__getitem__` returning modified columns when called with ``slice`` in Python 3.12 (:issue:`57500`) - Bug in :meth:`DataFrame.from_records` throwing a ``ValueError`` when passed an empty list in ``index`` (:issue:`58594`) +- Bug in printing :attr:`Index.names` and :attr:`MultiIndex.levels` would not escape single quotes (:issue:`60190`) Missing ^^^^^^^ From 10df8b48fd28805c68f58f2ed0ef15e708d81ee9 Mon Sep 17 00:00:00 2001 From: thedataninja1786 Date: Sat, 23 Nov 2024 17:20:22 +0200 Subject: [PATCH 14/14] Converted tests for string comparisons --- pandas/tests/io/formats/test_printing.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index 01e16b4228bf4..3b63011bf862e 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -15,17 +15,17 @@ @pytest.mark.parametrize( "input_names, expected_names", [ - (["'a", "b"], ["'a", "b"]), # Escape leading quote - (["test's", "b"], ["test's", "b"]), # Escape apostrophe - (["'test'", "b"], ["'test'", "b"]), # Escape surrounding quotes - (["test", "b'"], ["test", "b'"]), # Escape single quote - (["'test\n'", "b"], ["'test\n'", "b"]), # Escape and preserve newline + (["'a b"], "['\\'a b']"), # Escape leading quote + (["test's b"], "['test\\'s b']"), # Escape apostrophe + (["'test' b"], "['\\'test\\' b']"), # Escape surrounding quotes + (["test b'"], "['test b\\'']"), # Escape single quote + (["test\n' b"], "['test\\n\\' b']"), # Escape quotes, preserve newline ], ) def test_formatted_index_names(input_names, expected_names): # GH#60190 df = pd.DataFrame({name: [1, 2, 3] for name in input_names}).set_index(input_names) - formatted_names = df.index.names + formatted_names = str(df.index.names) assert formatted_names == expected_names