Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
762d80e
Add module for async support
RCoff Dec 22, 2025
d623964
Add client for (primarily) managing access token for user
RCoff Dec 22, 2025
c3d6a11
Bump version number, add httpx dependency
RCoff Dec 22, 2025
2915ea7
Remove support for passing in Smartsheet-python-sdk objects.
RCoff Dec 22, 2025
57ac85c
Remove unused dependencies, try using 'Literal' for type hinting
RCoff Dec 22, 2025
a48a5a0
Add Python 3.6.5 as a tested version
RCoff Dec 22, 2025
5c82e76
Add Python 3.7 as a tested version, remove Python 3.6.5
RCoff Dec 22, 2025
7c1fcfe
Add Python 3.13 as a tested version
RCoff Dec 22, 2025
5ffbb21
"Manually" install Python 3.7 for UV
RCoff Dec 22, 2025
4871aa1
Add Python 3.14 as a tested version, remove Python 3.7
RCoff Dec 22, 2025
db7edcc
Remove use of Literal
RCoff Dec 22, 2025
0401bf6
Remove use of Literal
RCoff Dec 22, 2025
b87ba8d
Update docstrings
RCoff Dec 22, 2025
5481e5c
Create BaseClient class, add tests
RCoff Dec 22, 2025
99c55d3
Remove requests as a dependency
RCoff Dec 29, 2025
f280266
Begin adding async client and tests
RCoff Dec 29, 2025
7e06507
Add pytest-asyncio dev dependency to facilitate async tests
RCoff Dec 29, 2025
290da4c
Expose clients at top-level module
RCoff Dec 29, 2025
f308cab
Move exceptions to utils module
RCoff Dec 29, 2025
93af52f
Move _do_request to new http file in utils, use httpx instead of requ…
RCoff Dec 29, 2025
7f00043
Move _do_request tests into http test file
RCoff Dec 29, 2025
0c5af8e
Fix Python version for linting
RCoff Dec 29, 2025
da02884
Make http util private
RCoff Dec 29, 2025
769c13e
Add additional exceptions
RCoff Dec 29, 2025
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
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Set uv & Python ${{ matrix.python-version }}
- name: Set uv & Python 3.12
uses: astral-sh/setup-uv@v6
with:
python-version: "3.10"
python-version: "3.12"

- name: Install dependencies
run: uv sync --locked --all-extras --dev
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
continue-on-error: true
strategy:
matrix:
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14" ]

steps:
- name: Checkout code
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ TODO:

* Python 3+ (Tested using 3.8+)
* Pandas >= 0.24.0
* Requests >= 2.0.0
* Httpx >= 0.28.1

## From PyPI

Expand All @@ -38,9 +38,9 @@ df = get_sheet_as_df(token='smartsheet_auth_token',
sheet_id=sheet_id_int)

# Using 'generic' function (without smartsheet-python-sdk)
df = get_as_df(type_='sheet',
df = get_as_df(object_type='sheet',
token='smartsheet_auth_token',
id_=sheet_id_int)
object_id=sheet_id_int)
```

Alternatively, sheet objects can be used from the ``smartsheet-python-sdk`` package:
Expand All @@ -56,7 +56,7 @@ sheet = smartsheet_client.Sheets.get_sheet(sheet_id_int)
df = get_sheet_as_df(sheet_obj=sheet)

# And using the 'generic' function
df = get_as_df(type_='sheet',
df = get_as_df(object_type='sheet',
obj=sheet)
```

Expand All @@ -72,9 +72,9 @@ df = get_report_as_df(token='smartsheet_auth_token',
report_id=report_id_int)

# Using 'generic' function (without smartsheet-python-sdk)
df = get_as_df(type_='report',
df = get_as_df(object_type='report',
token='smartsheet_auth_token',
id_=report_id_int)
object_id=report_id_int)
```

And using a report object from the ``smartsheet-python-sdk`` package:
Expand All @@ -90,6 +90,6 @@ report = smartsheet_client.Reports.get_report(report_id_int)
df = get_report_as_df(report_obj=report)

# And using the 'generic' function
df = get_as_df(type_='report',
df = get_as_df(object_type='report',
obj=report)
```
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "smartsheet-dataframe"
version = "0.3.7"
version = "1.0.0"
authors = [
{ name = "Ridge Coffman", email = "coffman.ridge@gmail.com" },
]
Expand All @@ -26,8 +26,8 @@ classifiers = [
"Topic :: Office/Business :: Financial :: Spreadsheet",
]
dependencies = [
"httpx>=0.22.0",
"pandas>=0.24.0",
"requests>=2.0.0"
]

[project.urls]
Expand Down Expand Up @@ -106,6 +106,7 @@ dev = [
"isort>=5.10.1",
"pyright>=0.0.13.post0",
"pytest>=7.0.1",
"pytest-asyncio>=0.16.0",
"pytest-cov>=4.0.0",
"python-dotenv>=0.20.0",
"ruff>=0.0.17",
Expand Down
4 changes: 4 additions & 0 deletions src/smartsheet_dataframe/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
"""Init file for smartsheet_dataframe module."""

from .aio.client import AsyncClient
from .client import Client
from .smartsheet_dataframe import (
get_as_df,
get_report_as_df,
get_sheet_as_df,
)

__all__ = [
"AsyncClient",
"Client",
"get_as_df",
"get_report_as_df",
"get_sheet_as_df",
Expand Down
Empty file.
79 changes: 79 additions & 0 deletions src/smartsheet_dataframe/aio/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Standard Imports
import logging
from typing import Optional

# 3rd-Party Imports
import pandas as pd

logger = logging.getLogger(__name__)


class AsyncClient:
__slots__ = ("token", "include_row_id", "include_parent_id")

def __init__(self, token: str, include_row_id: bool = True, include_parent_id: bool = True):
self.token = token
self.include_row_id = include_row_id
self.include_parent_id = include_parent_id

def get_sheet_as_df(self,
sheet_id: int,
include_row_id: Optional[bool] = None,
include_parent_id: Optional[bool] = None) -> pd.DataFrame:
"""Get a Smartsheet sheet as a Pandas DataFrame.

:param sheet_id: Smartsheet source sheet id to get
:type sheet_id: int

:param include_row_id: If True, will append a 'row_id' column to the dataframe
and populate with row id for each row in sheet
:type include_row_id: bool

:param include_parent_id: If True, will append a 'parent_id' column to the
dataframe and populate with parent ID for each nested row
:type include_parent_id: bool

:return: Pandas DataFrame with sheet data
:rtype: pd.DataFrame
"""

if include_row_id is None:
include_row_id = self.include_row_id
if include_parent_id is None:
include_parent_id = self.include_parent_id

return get_sheet_as_df(token=self.token,
sheet_id=sheet_id,
include_row_id=include_row_id,
include_parent_id=include_parent_id)

def get_report_as_df(self,
report_id: int,
include_row_id: Optional[bool] = None,
include_parent_id: Optional[bool] = None) -> pd.DataFrame:
"""Get a Smartsheet report as a Pandas DataFrame.

:param report_id: Smartsheet source report id to get
:type report_id: int

:param include_row_id: If True, will append a 'row_id' column to the dataframe
and populate with row id for each row in sheet
:type include_row_id: bool

:param include_parent_id: If True, will append a 'parent_id' column to the
dataframe and populate with parent ID for each nested row
:type include_parent_id: bool

:return: Pandas DataFrame with report data
:rtype: pd.DataFrame
"""

if include_row_id is None:
include_row_id = self.include_row_id
if include_parent_id is None:
include_parent_id = self.include_parent_id

return get_report_as_df(token=self.token,
report_id=report_id,
include_row_id=include_row_id,
include_parent_id=include_parent_id)
87 changes: 87 additions & 0 deletions src/smartsheet_dataframe/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Standard Imports
import logging
from typing import Optional

# 3rd-Party Imports
import pandas as pd

# Local Imports
from .smartsheet_dataframe import (
get_sheet_as_df,
get_report_as_df,
)

logger = logging.getLogger(__name__)


class BaseClient:
__slots__ = ("token", "include_row_id", "include_parent_id")

def __init__(self, token: str, include_row_id: bool = True, include_parent_id: bool = True):
self.token = token
self.include_row_id = include_row_id
self.include_parent_id = include_parent_id


class Client(BaseClient):
def get_sheet_as_df(self,
sheet_id: int,
include_row_id: Optional[bool] = None,
include_parent_id: Optional[bool] = None) -> pd.DataFrame:
"""Get a Smartsheet sheet as a Pandas DataFrame.

:param sheet_id: Smartsheet source sheet id to get
:type sheet_id: int

:param include_row_id: If True, will append a 'row_id' column to the dataframe
and populate with row id for each row in sheet
:type include_row_id: bool

:param include_parent_id: If True, will append a 'parent_id' column to the
dataframe and populate with parent ID for each nested row
:type include_parent_id: bool

:return: Pandas DataFrame with sheet data
:rtype: pd.DataFrame
"""

if include_row_id is None:
include_row_id = self.include_row_id
if include_parent_id is None:
include_parent_id = self.include_parent_id

return get_sheet_as_df(token=self.token,
sheet_id=sheet_id,
include_row_id=include_row_id,
include_parent_id=include_parent_id)

def get_report_as_df(self,
report_id: int,
include_row_id: Optional[bool] = None,
include_parent_id: Optional[bool] = None) -> pd.DataFrame:
"""Get a Smartsheet report as a Pandas DataFrame.

:param report_id: Smartsheet source report id to get
:type report_id: int

:param include_row_id: If True, will append a 'row_id' column to the dataframe
and populate with row id for each row in sheet
:type include_row_id: bool

:param include_parent_id: If True, will append a 'parent_id' column to the
dataframe and populate with parent ID for each nested row
:type include_parent_id: bool

:return: Pandas DataFrame with report data
:rtype: pd.DataFrame
"""

if include_row_id is None:
include_row_id = self.include_row_id
if include_parent_id is None:
include_parent_id = self.include_parent_id

return get_report_as_df(token=self.token,
report_id=report_id,
include_row_id=include_row_id,
include_parent_id=include_parent_id)
5 changes: 0 additions & 5 deletions src/smartsheet_dataframe/exceptions.py

This file was deleted.

Loading
Loading