diff --git a/gspread/utils.py b/gspread/utils.py index 59d25818d..ff5c255f6 100644 --- a/gspread/utils.py +++ b/gspread/utils.py @@ -118,6 +118,41 @@ class GridRangeType(StrEnum): ListOfLists = "ListOfLists" +class ValidationConditionType(StrEnum): + number_greater = "NUMBER_GREATER" + number_greater_than_eq = "NUMBER_GREATER_THAN_EQ" + number_less = "NUMBER_LESS" + number_less_than_eq = "NUMBER_LESS_THAN_EQ" + number_eq = "NUMBER_EQ" + number_not_eq = "NUMBER_NOT_EQ" + number_between = "NUMBER_BETWEEN" + number_not_between = "NUMBER_NOT_BETWEEN" + text_contains = "TEXT_CONTAINS" + text_not_contains = "TEXT_NOT_CONTAINS" + text_starts_with = "TEXT_STARTS_WITH" + text_ends_with = "TEXT_ENDS_WITH" + text_eq = "TEXT_EQ" + text_is_email = "TEXT_IS_EMAIL" + text_is_url = "TEXT_IS_URL" + date_eq = "DATE_EQ" + date_before = "DATE_BEFORE" + date_after = "DATE_AFTER" + date_on_or_before = "DATE_ON_OR_BEFORE" + date_on_or_after = "DATE_ON_OR_AFTER" + date_between = "DATE_BETWEEN" + date_not_between = "DATE_NOT_BETWEEN" + date_is_valid = "DATE_IS_VALID" + one_of_range = "ONE_OF_RANGE" + one_of_list = "ONE_OF_LIST" + blank = "BLANK" + not_blank = "NOT_BLANK" + custom_formula = "CUSTOM_FORMULA" + boolean = "BOOLEAN" + text_not_eq = "TEXT_NOT_EQ" + date_not_eq = "DATE_NOT_EQ" + filter_expression = "FILTER_EXPRESSION" + + def convert_credentials(credentials: Credentials) -> Credentials: module = credentials.__module__ cls = credentials.__class__.__name__ diff --git a/gspread/worksheet.py b/gspread/worksheet.py index 5710a4f83..bcee592b8 100644 --- a/gspread/worksheet.py +++ b/gspread/worksheet.py @@ -41,6 +41,7 @@ PasteOrientation, PasteType, T, + ValidationConditionType, ValueInputOption, ValueRenderOption, a1_range_to_grid_range, @@ -2091,12 +2092,14 @@ def add_protected_range( "description": description, "warningOnly": warning_only, "requestingUserCanEdit": requesting_user_can_edit, - "editors": None - if warning_only - else { - "users": editor_users_emails, - "groups": editor_groups_emails, - }, + "editors": ( + None + if warning_only + else { + "users": editor_users_emails, + "groups": editor_groups_emails, + } + ), } } } @@ -3201,3 +3204,88 @@ def cut_range( } return self.client.batch_update(self.spreadsheet_id, body) + + def add_validation( + self, + range: str, + condition_type: ValidationConditionType, + values: Iterable[Any], + inputMessage: Optional[str] = None, + strict: bool = False, + showCustomUi: bool = False, + ) -> Any: + """Adds a data validation rule to any given range. + + .. note:: + + ``condition_type`` values are explained here: `ConditionType`_ + + .. _ConditionType: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ConditionType + + + :param str source: The A1 notation of the source range to move + :param condition_type: The sort of condition to apply. + :param values: List of condition values. + :type values: Any + :param str inputMessage: Message to show for the validation. + :param bool strict: Whether to reject invalid data or not. + :param bool showCustomUi: Whether to show a custom UI(Dropdown) for list values. + + **Examples** + + .. code-block:: python + + import gspread + from gspread.utils import ValidationConditionType + + + ... + + ws = spreadsheet.sheet1 + + ws.add_validation( + 'A1', + ValidationConditionType.number_greater, + 10, + strict=True, + inputMessage='Value must be greater than 10', + ) + + ws.add_validation( + 'C2:C7', + ValidationConditionType.one_of_list, + 'Yes', + 'No', + showCustomUi=True + ) + """ + + if not isinstance(condition_type, ValidationConditionType): + raise TypeError( + "condition_type param should be a valid ValidationConditionType." + ) + + grid = a1_range_to_grid_range(range, self.id) + + body = { + "requests": [ + { + "setDataValidation": { + "range": grid, + "rule": { + "condition": { + "type": condition_type, + "values": [ + ({"userEnteredValue": value}) for value in values + ], + }, + "showCustomUi": showCustomUi, + "strict": strict, + "inputMessage": inputMessage, + }, + } + } + ], + } + + return self.client.batch_update(self.spreadsheet_id, body) diff --git a/tests/cassettes/WorksheetTest.test_add_validation.json b/tests/cassettes/WorksheetTest.test_add_validation.json new file mode 100644 index 000000000..a6902681d --- /dev/null +++ b/tests/cassettes/WorksheetTest.test_add_validation.json @@ -0,0 +1,539 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "POST", + "uri": "https://www.googleapis.com/drive/v3/files?supportsAllDrives=True", + "body": "{\"name\": \"Test WorksheetTest test_add_validation\", \"mimeType\": \"application/vnd.google-apps.spreadsheet\"}", + "headers": { + "User-Agent": [ + "python-requests/2.31.0" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Accept": [ + "*/*" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "105" + ], + "Content-Type": [ + "application/json" + ], + "authorization": [ + "" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Fri, 29 Mar 2024 06:00:41 GMT" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "Origin, X-Origin" + ], + "X-XSS-Protection": [ + "0" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Alt-Svc": [ + "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + ], + "Pragma": [ + "no-cache" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "Server": [ + "ESF" + ], + "content-length": [ + "192" + ] + }, + "body": { + "string": "{\n \"kind\": \"drive#file\",\n \"id\": \"1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA\",\n \"name\": \"Test WorksheetTest test_add_validation\",\n \"mimeType\": \"application/vnd.google-apps.spreadsheet\"\n}\n" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://sheets.googleapis.com/v4/spreadsheets/1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA?includeGridData=false", + "body": null, + "headers": { + "User-Agent": [ + "python-requests/2.31.0" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Accept": [ + "*/*" + ], + "Connection": [ + "keep-alive" + ], + "authorization": [ + "" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Fri, 29 Mar 2024 06:00:42 GMT" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "x-l2-request-path": [ + "l2-managed-6" + ], + "X-XSS-Protection": [ + "0" + ], + "Cache-Control": [ + "private" + ], + "Alt-Svc": [ + "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "Server": [ + "ESF" + ], + "content-length": [ + "3336" + ] + }, + "body": { + "string": "{\n \"spreadsheetId\": \"1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA\",\n \"properties\": {\n \"title\": \"Test WorksheetTest test_add_validation\",\n \"locale\": \"en_US\",\n \"autoRecalc\": \"ON_CHANGE\",\n \"timeZone\": \"Etc/GMT\",\n \"defaultFormat\": {\n \"backgroundColor\": {\n \"red\": 1,\n \"green\": 1,\n \"blue\": 1\n },\n \"padding\": {\n \"top\": 2,\n \"right\": 3,\n \"bottom\": 2,\n \"left\": 3\n },\n \"verticalAlignment\": \"BOTTOM\",\n \"wrapStrategy\": \"OVERFLOW_CELL\",\n \"textFormat\": {\n \"foregroundColor\": {},\n \"fontFamily\": \"arial,sans,sans-serif\",\n \"fontSize\": 10,\n \"bold\": false,\n \"italic\": false,\n \"strikethrough\": false,\n \"underline\": false,\n \"foregroundColorStyle\": {\n \"rgbColor\": {}\n }\n },\n \"backgroundColorStyle\": {\n \"rgbColor\": {\n \"red\": 1,\n \"green\": 1,\n \"blue\": 1\n }\n }\n },\n \"spreadsheetTheme\": {\n \"primaryFontFamily\": \"Arial\",\n \"themeColors\": [\n {\n \"colorType\": \"TEXT\",\n \"color\": {\n \"rgbColor\": {}\n }\n },\n {\n \"colorType\": \"BACKGROUND\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 1,\n \"green\": 1,\n \"blue\": 1\n }\n }\n },\n {\n \"colorType\": \"ACCENT1\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.25882354,\n \"green\": 0.52156866,\n \"blue\": 0.95686275\n }\n }\n },\n {\n \"colorType\": \"ACCENT2\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.91764706,\n \"green\": 0.2627451,\n \"blue\": 0.20784314\n }\n }\n },\n {\n \"colorType\": \"ACCENT3\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.9843137,\n \"green\": 0.7372549,\n \"blue\": 0.015686275\n }\n }\n },\n {\n \"colorType\": \"ACCENT4\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.20392157,\n \"green\": 0.65882355,\n \"blue\": 0.3254902\n }\n }\n },\n {\n \"colorType\": \"ACCENT5\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 1,\n \"green\": 0.42745098,\n \"blue\": 0.003921569\n }\n }\n },\n {\n \"colorType\": \"ACCENT6\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.27450982,\n \"green\": 0.7411765,\n \"blue\": 0.7764706\n }\n }\n },\n {\n \"colorType\": \"LINK\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.06666667,\n \"green\": 0.33333334,\n \"blue\": 0.8\n }\n }\n }\n ]\n }\n },\n \"sheets\": [\n {\n \"properties\": {\n \"sheetId\": 0,\n \"title\": \"Sheet1\",\n \"index\": 0,\n \"sheetType\": \"GRID\",\n \"gridProperties\": {\n \"rowCount\": 1000,\n \"columnCount\": 26\n }\n }\n }\n ],\n \"spreadsheetUrl\": \"https://docs.google.com/spreadsheets/d/1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA/edit\"\n}\n" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://sheets.googleapis.com/v4/spreadsheets/1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA?includeGridData=false", + "body": null, + "headers": { + "User-Agent": [ + "python-requests/2.31.0" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Accept": [ + "*/*" + ], + "Connection": [ + "keep-alive" + ], + "authorization": [ + "" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Fri, 29 Mar 2024 06:00:42 GMT" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "x-l2-request-path": [ + "l2-managed-6" + ], + "X-XSS-Protection": [ + "0" + ], + "Cache-Control": [ + "private" + ], + "Alt-Svc": [ + "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "Server": [ + "ESF" + ], + "content-length": [ + "3336" + ] + }, + "body": { + "string": "{\n \"spreadsheetId\": \"1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA\",\n \"properties\": {\n \"title\": \"Test WorksheetTest test_add_validation\",\n \"locale\": \"en_US\",\n \"autoRecalc\": \"ON_CHANGE\",\n \"timeZone\": \"Etc/GMT\",\n \"defaultFormat\": {\n \"backgroundColor\": {\n \"red\": 1,\n \"green\": 1,\n \"blue\": 1\n },\n \"padding\": {\n \"top\": 2,\n \"right\": 3,\n \"bottom\": 2,\n \"left\": 3\n },\n \"verticalAlignment\": \"BOTTOM\",\n \"wrapStrategy\": \"OVERFLOW_CELL\",\n \"textFormat\": {\n \"foregroundColor\": {},\n \"fontFamily\": \"arial,sans,sans-serif\",\n \"fontSize\": 10,\n \"bold\": false,\n \"italic\": false,\n \"strikethrough\": false,\n \"underline\": false,\n \"foregroundColorStyle\": {\n \"rgbColor\": {}\n }\n },\n \"backgroundColorStyle\": {\n \"rgbColor\": {\n \"red\": 1,\n \"green\": 1,\n \"blue\": 1\n }\n }\n },\n \"spreadsheetTheme\": {\n \"primaryFontFamily\": \"Arial\",\n \"themeColors\": [\n {\n \"colorType\": \"TEXT\",\n \"color\": {\n \"rgbColor\": {}\n }\n },\n {\n \"colorType\": \"BACKGROUND\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 1,\n \"green\": 1,\n \"blue\": 1\n }\n }\n },\n {\n \"colorType\": \"ACCENT1\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.25882354,\n \"green\": 0.52156866,\n \"blue\": 0.95686275\n }\n }\n },\n {\n \"colorType\": \"ACCENT2\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.91764706,\n \"green\": 0.2627451,\n \"blue\": 0.20784314\n }\n }\n },\n {\n \"colorType\": \"ACCENT3\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.9843137,\n \"green\": 0.7372549,\n \"blue\": 0.015686275\n }\n }\n },\n {\n \"colorType\": \"ACCENT4\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.20392157,\n \"green\": 0.65882355,\n \"blue\": 0.3254902\n }\n }\n },\n {\n \"colorType\": \"ACCENT5\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 1,\n \"green\": 0.42745098,\n \"blue\": 0.003921569\n }\n }\n },\n {\n \"colorType\": \"ACCENT6\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.27450982,\n \"green\": 0.7411765,\n \"blue\": 0.7764706\n }\n }\n },\n {\n \"colorType\": \"LINK\",\n \"color\": {\n \"rgbColor\": {\n \"red\": 0.06666667,\n \"green\": 0.33333334,\n \"blue\": 0.8\n }\n }\n }\n ]\n }\n },\n \"sheets\": [\n {\n \"properties\": {\n \"sheetId\": 0,\n \"title\": \"Sheet1\",\n \"index\": 0,\n \"sheetType\": \"GRID\",\n \"gridProperties\": {\n \"rowCount\": 1000,\n \"columnCount\": 26\n }\n }\n }\n ],\n \"spreadsheetUrl\": \"https://docs.google.com/spreadsheets/d/1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA/edit\"\n}\n" + } + } + }, + { + "request": { + "method": "POST", + "uri": "https://sheets.googleapis.com/v4/spreadsheets/1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA/values/%27Sheet1%27:clear", + "body": null, + "headers": { + "User-Agent": [ + "python-requests/2.31.0" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Accept": [ + "*/*" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "0" + ], + "authorization": [ + "" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Fri, 29 Mar 2024 06:00:42 GMT" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "x-l2-request-path": [ + "l2-managed-6" + ], + "X-XSS-Protection": [ + "0" + ], + "Cache-Control": [ + "private" + ], + "Alt-Svc": [ + "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "Server": [ + "ESF" + ], + "content-length": [ + "107" + ] + }, + "body": { + "string": "{\n \"spreadsheetId\": \"1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA\",\n \"clearedRange\": \"Sheet1!A1:Z1000\"\n}\n" + } + } + }, + { + "request": { + "method": "POST", + "uri": "https://sheets.googleapis.com/v4/spreadsheets/1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA:batchUpdate", + "body": "{\"requests\": [{\"setDataValidation\": {\"range\": {\"startRowIndex\": 0, \"endRowIndex\": 1, \"startColumnIndex\": 0, \"endColumnIndex\": 1, \"sheetId\": 0}, \"rule\": {\"condition\": {\"type\": \"ONE_OF_LIST\", \"values\": [{\"userEnteredValue\": \"y\"}]}, \"showCustomUi\": false, \"strict\": true, \"inputMessage\": \"n\"}}}]}", + "headers": { + "User-Agent": [ + "python-requests/2.31.0" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Accept": [ + "*/*" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "293" + ], + "Content-Type": [ + "application/json" + ], + "authorization": [ + "" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Fri, 29 Mar 2024 06:00:43 GMT" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "x-l2-request-path": [ + "l2-managed-6" + ], + "X-XSS-Protection": [ + "0" + ], + "Cache-Control": [ + "private" + ], + "Alt-Svc": [ + "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "Server": [ + "ESF" + ], + "content-length": [ + "97" + ] + }, + "body": { + "string": "{\n \"spreadsheetId\": \"1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA\",\n \"replies\": [\n {}\n ]\n}\n" + } + } + }, + { + "request": { + "method": "PUT", + "uri": "https://sheets.googleapis.com/v4/spreadsheets/1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA/values/%27Sheet1%27%21A1?valueInputOption=RAW", + "body": "{\"values\": \"X\", \"majorDimension\": null}", + "headers": { + "User-Agent": [ + "python-requests/2.31.0" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Accept": [ + "*/*" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "39" + ], + "Content-Type": [ + "application/json" + ], + "authorization": [ + "" + ] + } + }, + "response": { + "status": { + "code": 400, + "message": "Bad Request" + }, + "headers": { + "Date": [ + "Fri, 29 Mar 2024 06:00:43 GMT" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "x-l2-request-path": [ + "l2-managed-6" + ], + "X-XSS-Protection": [ + "0" + ], + "Cache-Control": [ + "private" + ], + "Alt-Svc": [ + "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "Server": [ + "ESF" + ], + "content-length": [ + "491" + ] + }, + "body": { + "string": "{\n \"error\": {\n \"code\": 400,\n \"message\": \"Invalid value at 'data.values' (type.googleapis.com/google.protobuf.ListValue), \\\"X\\\"\",\n \"status\": \"INVALID_ARGUMENT\",\n \"details\": [\n {\n \"@type\": \"type.googleapis.com/google.rpc.BadRequest\",\n \"fieldViolations\": [\n {\n \"field\": \"data.values\",\n \"description\": \"Invalid value at 'data.values' (type.googleapis.com/google.protobuf.ListValue), \\\"X\\\"\"\n }\n ]\n }\n ]\n }\n}\n" + } + } + }, + { + "request": { + "method": "DELETE", + "uri": "https://www.googleapis.com/drive/v3/files/1yOY1U4tsuCpKdLXnrrfpGtUtmIFCHLzXbYVJrbLlmCA?supportsAllDrives=True", + "body": null, + "headers": { + "User-Agent": [ + "python-requests/2.31.0" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Accept": [ + "*/*" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "0" + ], + "authorization": [ + "" + ] + } + }, + "response": { + "status": { + "code": 204, + "message": "No Content" + }, + "headers": { + "Date": [ + "Fri, 29 Mar 2024 06:00:44 GMT" + ], + "Vary": [ + "Origin, X-Origin" + ], + "Content-Length": [ + "0" + ], + "X-XSS-Protection": [ + "0" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Alt-Svc": [ + "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000" + ], + "Pragma": [ + "no-cache" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "Content-Type": [ + "text/html" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "Server": [ + "ESF" + ] + }, + "body": { + "string": "" + } + } + } + ] +} diff --git a/tests/worksheet_test.py b/tests/worksheet_test.py index 1c2e9b31d..6ed3c2d49 100644 --- a/tests/worksheet_test.py +++ b/tests/worksheet_test.py @@ -1871,3 +1871,19 @@ def test_get_and_get_values_have_same_signature(self): # get_all_values should be a carbon copy of get_values self.assertEqual(sig_get_values, sig_get_all_values) + + @pytest.mark.vcr() + def test_add_validation(self): + sheet = self.sheet + self.assertDictEqual( + sheet.add_validation( + "A1", + utils.ValidationConditionType.one_of_list, + "y", + "n", + strict=True, + ), + {"spreadsheetId": self.spreadsheet.id, "replies": [{}]}, + ) + + self.assertRaises(APIError, sheet.update, values="X", range_name="A1")