From 1b64098acc9c4aab8d336627e47ba18332b93997 Mon Sep 17 00:00:00 2001 From: masterPiece93 Date: Thu, 6 Nov 2025 13:59:29 +0530 Subject: [PATCH 1/3] prepared get_gsheet_data function for release --- src/gsheet_tools/__init__.py | 6 ++- src/gsheet_tools/_tools.py | 25 ++++++++--- tests/test_tools.py | 84 ++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 7 deletions(-) diff --git a/src/gsheet_tools/__init__.py b/src/gsheet_tools/__init__.py index af0b2e5..b0f8a67 100644 --- a/src/gsheet_tools/__init__.py +++ b/src/gsheet_tools/__init__.py @@ -22,7 +22,7 @@ - prepare_dataframe: Converts Google Sheets data into a pandas DataFrame. Metadata: -- Version: 0.1.1 +- Version: 0.2.0 - Author: Ankit Yadav - Email: ankit8290@gmail.com """ @@ -36,6 +36,7 @@ UrlResolver, check_sheet_origin, get_gid_sheets_data, + get_gsheet_data, is_valid_google_url, prepare_dataframe, ) @@ -48,10 +49,11 @@ "SheetOrigins", "SheetMimetype", "get_gid_sheets_data", + "get_gsheet_data", "check_sheet_origin", "is_valid_google_url", "prepare_dataframe", ] -__version__ = "0.1.1" +__version__ = "0.2.0" __author__ = "Ankit Yadav" __email__ = "ankit8290@gmail.com" diff --git a/src/gsheet_tools/_tools.py b/src/gsheet_tools/_tools.py index d63067c..bffa6f4 100644 --- a/src/gsheet_tools/_tools.py +++ b/src/gsheet_tools/_tools.py @@ -275,8 +275,17 @@ def get_gsheet_data( Raises: Exceptions.GsheetToolsArgumentError: If invalid arguments are passed. + + Warning: + * without_headers parameter won't take effect when custom_tabular_range is set . + * within not_found_priority values , every value is coerced to string . """ + __by__ = {'gid', 'sheet_name', 'sheet_position'} + if by not in __by__: + raise Exceptions.GsheetToolsArgumentError( + "[by]", f"value `{by=}` is invalid, should be any one of `{','.join(__by__)}`." + ) if by == "gid" and gid is None: raise Exceptions.GsheetToolsArgumentError( "[by,gid]", f"with `{by=}` you cannot pass `{gid=}`." @@ -289,7 +298,10 @@ def get_gsheet_data( raise Exceptions.GsheetToolsArgumentError( "[by,sheet_position]", f"with `{by=}` you cannot pass `{sheet_position=}`." ) - + if not_found_priority and not all([v in __by__ for v in not_found_priority]): + raise Exceptions.GsheetToolsArgumentError( + "[not_found_priority]", f"not_found_priority should be any of `{','.join(__by__)}`." + ) # fetch metadata on google sheet spreadsheet_metadata = sheet.get( # type: ignore[attr-defined] spreadsheetId=file_id, @@ -312,7 +324,7 @@ def get_gsheet_data( def _find( indivisual_sheet_properties: list, search_on_key: str, search_for_value: str ) -> Optional[dict]: - """ """ + """ [Nested]""" found_sheet_properties = None for indivisual_sheet in indivisual_sheet_properties: if str(indivisual_sheet["properties"][search_on_key]) == search_for_value: @@ -321,7 +333,7 @@ def _find( return found_sheet_properties def _fallback_safe_find_proprties(spreadsheet_metadata: dict) -> Optional[dict]: - """ """ + """ [Nested]""" found_sheet_properties = _find( spreadsheet_metadata["sheets"], search_on_key, search_for_value ) @@ -354,8 +366,11 @@ def _fallback_safe_find_proprties(spreadsheet_metadata: dict) -> Optional[dict]: # properties found sheet_title = found_sheet_properties.get("title") # type: ignore[assignment] _range = f"{sheet_title}" - if without_headers: - _range = _range + "!" + "A2:z999999" + if custom_tabular_range: + _range = _range + "!" + ":".join(custom_tabular_range) + else: + if without_headers: + _range = _range + "!" + f"A2:z999999" return sheet_title, _fetch_data(sheet, file_id, cell_range=_range) # default return return sheet_title, sheet_data diff --git a/tests/test_tools.py b/tests/test_tools.py index e622973..bf3ff2c 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -296,3 +296,87 @@ def test_get_gsheet_data_invalid_arguments_t3(): mock_service = MagicMock() with pytest.raises(Exceptions.GsheetToolsArgumentError, match=r"Argument::[by,sheet_position]|with `by='sheet_position'` you cannot pass `sheet_position=None`"): get_gsheet_data(mock_service, "file_id", by="sheet_position", sheet_position=None) + + +def test_get_gsheet_data_invalid_by_argument(): + """ + Test invalid 'by' argument in get_gsheet_data. + """ + mock_service = MagicMock() + with pytest.raises(Exceptions.GsheetToolsArgumentError): + get_gsheet_data(mock_service, "file_id", by="invalid_by") + + +def test_get_gsheet_data_empty_sheets_metadata(): + """ + Test get_gsheet_data when the sheets metadata is empty. + """ + mock_service = MagicMock() + mock_service.get().execute.return_value = {"sheets": []} + title, data = get_gsheet_data(mock_service, "file_id", by="gid", gid="67890") + assert title == "" + assert data == [] + + +def test_get_gsheet_data_empty_values(): + """ + Test get_gsheet_data when the sheet values are empty. + """ + mock_service = MagicMock() + mock_service.get().execute.return_value = { + "sheets": [{"properties": {"sheetId": "67890", "title": "Sheet1"}}] + } + mock_service.values().get().execute.return_value = {} + title, data = get_gsheet_data(mock_service, "file_id", by="gid", gid="67890") + assert title == "Sheet1" + assert data == [] + + +def test_get_gsheet_data_not_found_priority_invalid_key(): + """ + Test get_gsheet_data with an invalid key in not_found_priority. + """ + mock_service = MagicMock() + mock_service.get().execute.return_value = { + "sheets": [{"properties": {"sheetId": "67890", "title": "Sheet1"}}] + } + with pytest.raises(Exceptions.GsheetToolsArgumentError): + title, data = get_gsheet_data( + mock_service, + "file_id", + by="gid", + gid="99999", + not_found_priority={"invalid_key": "value"}, + ) + +def test_prepare_dataframe_with_non_tabular_data(): + """ + Test prepare_dataframe with non-tabular data. + """ + data = [["Name", "Age"], ["Alice", 30], ["Bob"]] + # with pytest.raises(Exceptions.GoogleSpreadsheetProcessingError): + prepare_dataframe(data) + + +def test_prepare_dataframe_with_invalid_data_type(): + """ + Test prepare_dataframe with invalid data type. + """ + data = "invalid_data" + with pytest.raises(Exceptions.GoogleSpreadsheetProcessingError): + prepare_dataframe(data) + + +def test_check_sheet_origin_invalid_mimetype(): + """ + Test check_sheet_origin with an invalid mimetype. + """ + mock_service = MagicMock() + mock_service.files().get().execute.return_value = { + "mimeType": "application/unknown", + "originalFilename": None, + } + origin, details = check_sheet_origin(mock_service, "file_id") + assert origin == SheetOrigins.UPLOADED_NON_CONVERTED + assert details.is_parsable is False + assert details.original_extension == "unidentified" From fb017792c6b157b9bea36d2860ff41af95e11ee9 Mon Sep 17 00:00:00 2001 From: masterPiece93 Date: Thu, 6 Nov 2025 16:56:17 +0530 Subject: [PATCH 2/3] fixing linting issues --- src/gsheet_tools/_tools.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/gsheet_tools/_tools.py b/src/gsheet_tools/_tools.py index bffa6f4..a990bd6 100644 --- a/src/gsheet_tools/_tools.py +++ b/src/gsheet_tools/_tools.py @@ -281,10 +281,11 @@ def get_gsheet_data( * within not_found_priority values , every value is coerced to string . """ - __by__ = {'gid', 'sheet_name', 'sheet_position'} + __by__ = {"gid", "sheet_name", "sheet_position"} if by not in __by__: raise Exceptions.GsheetToolsArgumentError( - "[by]", f"value `{by=}` is invalid, should be any one of `{','.join(__by__)}`." + "[by]", + f"value `{by=}` is invalid, should be any one of `{','.join(__by__)}`.", ) if by == "gid" and gid is None: raise Exceptions.GsheetToolsArgumentError( @@ -300,7 +301,8 @@ def get_gsheet_data( ) if not_found_priority and not all([v in __by__ for v in not_found_priority]): raise Exceptions.GsheetToolsArgumentError( - "[not_found_priority]", f"not_found_priority should be any of `{','.join(__by__)}`." + "[not_found_priority]", + f"not_found_priority should be any of `{','.join(__by__)}`.", ) # fetch metadata on google sheet spreadsheet_metadata = sheet.get( # type: ignore[attr-defined] @@ -324,7 +326,7 @@ def get_gsheet_data( def _find( indivisual_sheet_properties: list, search_on_key: str, search_for_value: str ) -> Optional[dict]: - """ [Nested]""" + """[Nested]""" found_sheet_properties = None for indivisual_sheet in indivisual_sheet_properties: if str(indivisual_sheet["properties"][search_on_key]) == search_for_value: @@ -333,7 +335,7 @@ def _find( return found_sheet_properties def _fallback_safe_find_proprties(spreadsheet_metadata: dict) -> Optional[dict]: - """ [Nested]""" + """[Nested]""" found_sheet_properties = _find( spreadsheet_metadata["sheets"], search_on_key, search_for_value ) @@ -370,7 +372,7 @@ def _fallback_safe_find_proprties(spreadsheet_metadata: dict) -> Optional[dict]: _range = _range + "!" + ":".join(custom_tabular_range) else: if without_headers: - _range = _range + "!" + f"A2:z999999" + _range = _range + "!" + "A2:z999999" return sheet_title, _fetch_data(sheet, file_id, cell_range=_range) # default return return sheet_title, sheet_data From 064f5f084cad1af71e1fd910691d6bcdebca0853 Mon Sep 17 00:00:00 2001 From: masterPiece93 Date: Thu, 6 Nov 2025 17:05:20 +0530 Subject: [PATCH 3/3] [fix-lint][added deprecation warning for get_gid_sheets_data] --- src/gsheet_tools/__init__.py | 2 +- src/gsheet_tools/_tools.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gsheet_tools/__init__.py b/src/gsheet_tools/__init__.py index b0f8a67..d207ee6 100644 --- a/src/gsheet_tools/__init__.py +++ b/src/gsheet_tools/__init__.py @@ -28,8 +28,8 @@ """ from gsheet_tools._exceptions import GsheetToolExceptionsBase +from gsheet_tools._tools import Exceptions # all public assistive tools from gsheet_tools._tools import ( - Exceptions, # all public assistive tools NameFormatter, SheetMimetype, SheetOrigins, diff --git a/src/gsheet_tools/_tools.py b/src/gsheet_tools/_tools.py index a990bd6..f3a6439 100644 --- a/src/gsheet_tools/_tools.py +++ b/src/gsheet_tools/_tools.py @@ -28,6 +28,7 @@ import dataclasses import re +import warnings from collections import namedtuple from enum import Enum from typing import Any, Dict, List, NamedTuple, Optional, Tuple @@ -218,7 +219,12 @@ def get_gid_sheets_data( Raises: Exception: If the sheet is not found. """ - + warnings.warn( + "get_gid_sheets_data will be deprecated soon" + "Please use get_gsheet_data instead", + PendingDeprecationWarning, + stacklevel=2, + ) spreadsheet_metadata = sheet.get( # type: ignore[attr-defined] spreadsheetId=sheet_id, fields="sheets.properties", # Request only the properties of each sheet