From fe425b995364263ddb8e58138477dab1523c9817 Mon Sep 17 00:00:00 2001 From: Mike Corrigan Date: Tue, 3 Sep 2024 09:19:20 -0600 Subject: [PATCH 1/3] added conditional formatting logic --- gspread/spreadsheet.py | 16 ++++++++++++++++ gspread/worksheet.py | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/gspread/spreadsheet.py b/gspread/spreadsheet.py index 236347258..13bff4379 100644 --- a/gspread/spreadsheet.py +++ b/gspread/spreadsheet.py @@ -718,6 +718,22 @@ def update_locale(self, locale: str) -> Any: self._properties["locale"] = locale return res + def list_conditional_formatting_rules(self, sheetid: int) -> List[Any]: + """Lists the spreadsheet's conditional formats""" + sheets: List[Mapping[str, Any]] = self.fetch_sheet_metadata( + params={"fields": "sheets.properties,sheets.conditionalFormats"} + )["sheets"] + + try: + sheet = finditem( + lambda sheet: sheet["properties"]["sheetId"] == sheetid, sheets + ) + + except StopIteration: + raise WorksheetNotFound("worksheet id {} not found".format(sheetid)) + + return sheet.get("conditionalFormats", []) + def list_protected_ranges(self, sheetid: int) -> List[Any]: """Lists the spreadsheet's protected named ranges""" sheets: List[Mapping[str, Any]] = self.fetch_sheet_metadata( diff --git a/gspread/worksheet.py b/gspread/worksheet.py index 463a72786..fdcdd02e0 100644 --- a/gspread/worksheet.py +++ b/gspread/worksheet.py @@ -2126,6 +2126,26 @@ def delete_protected_range(self, id: str) -> JSONResponse: } return self.client.batch_update(self.spreadsheet_id, body) + + def delete_conditional_formatting(self, index: int) -> JSONResponse: + """Delete conditional formatting rule identified by the index ``index``. + + To retrieve the ID of a conditional formatting rule use the following method + to list them all: :func:`~gspread.Spreadsheet.list_conditional_formatting_rules` + """ + + body = { + "requests": [ + { + "deleteConditionalFormatRule": { + "sheetId": self.id, + "index": index, + } + } + ] + } + + return self.client.batch_update(self.spreadsheet_id, body) def delete_dimension( self, dimension: Dimension, start_index: int, end_index: Optional[int] = None From b80929d192e486b8677a9d0ff2bd6f7660ce0951 Mon Sep 17 00:00:00 2001 From: Mike Corrigan Date: Tue, 3 Sep 2024 09:28:22 -0600 Subject: [PATCH 2/3] added some tests, changed a name --- gspread/worksheet.py | 2 +- tests/spreadsheet_test.py | 11 +++++++++++ tests/worksheet_test.py | 24 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/gspread/worksheet.py b/gspread/worksheet.py index fdcdd02e0..6f6e6b013 100644 --- a/gspread/worksheet.py +++ b/gspread/worksheet.py @@ -2127,7 +2127,7 @@ def delete_protected_range(self, id: str) -> JSONResponse: return self.client.batch_update(self.spreadsheet_id, body) - def delete_conditional_formatting(self, index: int) -> JSONResponse: + def delete_conditional_formatting_rule(self, index: int) -> JSONResponse: """Delete conditional formatting rule identified by the index ``index``. To retrieve the ID of a conditional formatting rule use the following method diff --git a/tests/spreadsheet_test.py b/tests/spreadsheet_test.py index 79d78ac82..a9d58ba42 100644 --- a/tests/spreadsheet_test.py +++ b/tests/spreadsheet_test.py @@ -235,3 +235,14 @@ def test_export_spreadsheet(self): self.assertEqual( values[0], res_values, "exported values are not the value initially set" ) + + @pytest.mark.vcr() + def test_listing_conditional_format_rules(self): + """Test listing conditional format rules of a spreadsheet""" + + worksheet = self.spreadsheet.sheet1 + worksheet.format("A1", {"backgroundColor": {"red": 1.0}}) + + rules = self.spreadsheet.list_conditional_format_rules(worksheet.id) + + self.assertEqual(len(rules), 1) \ No newline at end of file diff --git a/tests/worksheet_test.py b/tests/worksheet_test.py index 614575671..3f0422eba 100644 --- a/tests/worksheet_test.py +++ b/tests/worksheet_test.py @@ -1927,3 +1927,27 @@ def test_add_validation(self): # Further ensure we are able to access the exception's properties after pickling reloaded_exception = pickle.loads(pickle.dumps(ex.exception)) # nosec self.assertEqual(reloaded_exception.args[0]["status"], "INVALID_ARGUMENT") + + @pytest.mark.vcr() + def test_delete_conditional_formatting_rule(self): + sheet = self.sheet + spreadsheet = self.spreadsheet + + # add a conditional format rule to the spreadsheet + spreadsheet.format( + "A1:A2", + { + "backgroundColor": {"green": 1, "blue": 1}, + }, + ) + + # list the conditions on the spreadsheet + rules = spreadsheet.list_conditional_formatting_rules(0) + self.assertEqual(len(rules), 1) + + # delete the first rule by index + sheet.delete_conditional_formatting_rule(0) + + # verify rule was removed + rules = spreadsheet.list_conditional_formatting_rules(0) + self.assertEqual(len(rules), 0) \ No newline at end of file From bc2d13f471530da20ede60ef640ea4b80f6d8cbf Mon Sep 17 00:00:00 2001 From: alifeee Date: Mon, 9 Sep 2024 17:16:26 +0100 Subject: [PATCH 3/3] fix misspelt references --- tests/spreadsheet_test.py | 4 ++-- tests/worksheet_test.py | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/spreadsheet_test.py b/tests/spreadsheet_test.py index a9d58ba42..f3ef667d2 100644 --- a/tests/spreadsheet_test.py +++ b/tests/spreadsheet_test.py @@ -243,6 +243,6 @@ def test_listing_conditional_format_rules(self): worksheet = self.spreadsheet.sheet1 worksheet.format("A1", {"backgroundColor": {"red": 1.0}}) - rules = self.spreadsheet.list_conditional_format_rules(worksheet.id) + rules = self.spreadsheet.list_conditional_formatting_rules(worksheet.id) - self.assertEqual(len(rules), 1) \ No newline at end of file + self.assertEqual(len(rules), 1) diff --git a/tests/worksheet_test.py b/tests/worksheet_test.py index 3f0422eba..19d3cfeea 100644 --- a/tests/worksheet_test.py +++ b/tests/worksheet_test.py @@ -1932,9 +1932,10 @@ def test_add_validation(self): def test_delete_conditional_formatting_rule(self): sheet = self.sheet spreadsheet = self.spreadsheet + worksheet = self.spreadsheet.sheet1 # add a conditional format rule to the spreadsheet - spreadsheet.format( + worksheet.format( "A1:A2", { "backgroundColor": {"green": 1, "blue": 1}, @@ -1942,12 +1943,12 @@ def test_delete_conditional_formatting_rule(self): ) # list the conditions on the spreadsheet - rules = spreadsheet.list_conditional_formatting_rules(0) + rules = spreadsheet.list_conditional_formatting_rules(0) self.assertEqual(len(rules), 1) # delete the first rule by index sheet.delete_conditional_formatting_rule(0) # verify rule was removed - rules = spreadsheet.list_conditional_formatting_rules(0) - self.assertEqual(len(rules), 0) \ No newline at end of file + rules = spreadsheet.list_conditional_formatting_rules(0) + self.assertEqual(len(rules), 0)