Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/gsheet_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,21 @@
- 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
"""

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,
UrlResolver,
check_sheet_origin,
get_gid_sheets_data,
get_gsheet_data,
is_valid_google_url,
prepare_dataframe,
)
Expand All @@ -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"
35 changes: 29 additions & 6 deletions src/gsheet_tools/_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -275,8 +281,18 @@ 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=}`."
Expand All @@ -289,7 +305,11 @@ 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,
Expand All @@ -312,7 +332,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:
Expand All @@ -321,7 +341,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
)
Expand Down Expand Up @@ -354,8 +374,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 + "!" + "A2:z999999"
return sheet_title, _fetch_data(sheet, file_id, cell_range=_range)
# default return
return sheet_title, sheet_data
Expand Down
84 changes: 84 additions & 0 deletions tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Loading