SmartSpread
Python library for Google Sheets operations with automatic type inference, caching, and multiple data format support. Built on gspread.
Core Concepts
Two main classes:
SmartSpread: Represents a Google Sheets spreadsheet, manages authentication and tab accessSmartTab: Represents a single worksheet tab, handles data read/write operations
Three data formats:
DataFrame: pandas DataFrame (default) - best for data manipulationdict: List of dictionaries - each row is a dict with column names as keyslist: List of lists - first row is headers, remaining rows are data
Type inference:
- Empty cells →
None - Integers → nullable
Int64dtype (preservesNone) - Floats →
float64 - Strings →
objectdtype - Empty columns → inferred as needed when data is added
Caching behavior:
- Data is cached after first read to minimize API calls
- Hash comparison prevents unnecessary writes
- Use
refresh()to reload from Google Sheets after external changes
Installation & Setup
pip install smartspread
Authentication requirements:
- Google Cloud Project with Sheets API enabled
- Service account credentials JSON file
- Spreadsheet shared with service account email
Usage Patterns
Basic workflow
from smartspread import SmartSpread
spread = SmartSpread(
sheet_identifier="spreadsheet-id-or-name",
key_file="credentials.json"
)
tab = spread.tab("MyTab") # Get or create tab
tab.data["new_column"] = "value" # Modify DataFrame
tab.write_data(overwrite_tab=True) # Write to Sheets
Data format selection
tab_df = spread.tab("Sheet1", data_format="DataFrame") # pandas DataFrame
tab_dict = spread.tab("Sheet2", data_format="dict") # [{"col": "val"}, ...]
tab_list = spread.tab("Sheet3", data_format="list") # [["header"], ["val"], ...]
Update or insert rows
# Updates existing row where ID=123, or inserts new row if not found
tab.update_row_by_column_pattern(
column="ID",
value=123,
updates={"Status": "completed", "Date": "2024-01-01"}
)
tab.write_data(overwrite_tab=True)
Filter and refresh
filtered = tab.filter_rows_by_column("Name", "Alice") # Returns DataFrame
tab.refresh() # Reload from Sheets after external changes
API Reference
SmartSpread(sheet_identifier, key_file=None, service_account_data=None, user_email=None)
Constructor parameters:
sheet_identifier: Spreadsheet ID or namekey_file: Path to service account JSON credentialsservice_account_data: Dict of credentials (alternative to key_file)user_email: Email for user-based auth (alternative to service account)
Methods:
tab(tab_name, data_format="DataFrame", keep_number_formatting=False)→ SmartTabrefresh()→ None (clears cache, reloads metadata)grant_access(email, role="owner")→ None
Properties:
tab_names→ list[str]url→ strtab_exists(tab_name)→ bool
SmartTab
Attributes:
data: DataFrame | list[dict] | list[list] (mutable, modify directly)tab_name: strdata_format: "DataFrame" | "dict" | "list"
Methods:
read_data()→ DataFrame | list[dict] | list[list]write_data(overwrite_tab=False, as_table=False)→ Noneupdate_row_by_column_pattern(column, value, updates)→ None (modifiesdatain-place)filter_rows_by_column(column, pattern)→ DataFramerefresh()→ None (reloads from Sheets)
Important Implementation Details
Type handling:
- Empty cells →
None(not empty string) - Nullable integers use
Int64dtype (notint64) - Mixed-type columns automatically convert to
objectdtype when needed pd.NAvalues are sanitized toNonein dict/list formats- NaN values are converted to empty strings before writing to Sheets
Write behavior:
write_data()only writes if data hash has changedoverwrite_tab=Trueclears entire tab before writingoverwrite_tab=Falseupdates only the data rangeas_table=Trueadds header formatting and freeze
Rate limits:
- Google Sheets API: 60 requests/minute (free tier)
- Caching minimizes API calls automatically
Error handling:
- Empty tabs raise
ValueErroron read - Missing columns are auto-created with
Nonevalues - Type mismatches trigger automatic dtype conversion
Changelog
v1.1.5 (2024)
- Fixed: InvalidJSONError with NaN values in dict format by sanitizing in _data_as_list dict branch
v1.1.4 (2024)
- Fixed: TypeError when writing strings to float64 columns in update_row_by_column_pattern
- Fixed: InvalidJSONError with NaN values in write_data by converting to object dtype before fillna
v1.1.3 (2024)
- Fixed: pd.NA values sanitized to None in list/dict formats
v1.1.2 (2024)
- Changed: Package renamed to smartspread (no underscore)
v1.1.1 (2024)
- Fixed: JSON serialization with Int64 columns containing pd.NA
Links
- GitHub: https://github.com/Redundando/smart_spread
- PyPI: https://pypi.org/project/smartspread/
- License: MIT
Metadata
Release files for smartspread 1.1.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| smartspread-1.1.5.tar.gz | 13.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| smartspread-1.1.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.0 kB
Release files / smartspread-1.1.5.tar.gz
| Download URL | smartspread-1.1.5.tar.gz |
|---|---|
| Size | 13.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
34c55a9c6bd6851f31ea83fb3a432371de0bc09acacf75cc9559a5723ba98e8d
|
|
BLAKE2b-256 checksum How to use checksums |
9bcbddaacdb72750656e1de4d35b26959e5c0d4663f510d888fd3100864b7f80
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Release files / smartspread-1.1.5-py3-none-any.whl
| Download URL | smartspread-1.1.5-py3-none-any.whl |
|---|---|
| Size | 10.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5a45e2055d35f3c3dc2ab1b74408858cf7c57d464ff3f0fe490700d6ebba33dc
|
|
BLAKE2b-256 checksum How to use checksums |
7c6b7b0077927243506218ef4bd2fb4f3a6f2e2d5b9bbe8c971e7efa03c21bba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|