read-google-sheet
Load public Google Sheets directly into Polars LazyFrame or DataFrame — with railway-oriented error handling via polars-result.
Requires Python 3.14+
Features
- 📊 Polars-native — returns
LazyFrameby default,DataFrameon request - 🚂 Railway-oriented — every operation returns
Result[T, Exception], never raises - ✅ Validated — sheet ID and name are validated before any network request
- 📦 Minimal dependencies — Polars, requests, polars-result
Installation
uv add read-google-sheet
pip install read-google-sheet
Quick Start
from polars_result import Ok, Err
from read_google_sheet import read_google_sheet
result = read_google_sheet(
sheet_id="1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms",
sheet_name="Sheet1",
)
match result:
case Ok(lf):
print(lf.collect())
case Err(e):
print(f"Failed: {e}")
API Reference
read_google_sheet
def read_google_sheet(
sheet_id: str,
sheet_name: str,
as_dataframe: bool = False,
parse_dates: bool = True,
) -> Result[pl.LazyFrame | pl.DataFrame, Exception]
| Parameter | Description |
|---|---|
sheet_id |
44-character Google Sheet ID from the sheet URL |
sheet_name |
Tab name within the spreadsheet |
as_dataframe |
Return a collected DataFrame instead of a LazyFrame |
parse_dates |
Attempt to parse date columns automatically |
GoogleSheetConfig
Low-level dataclass for direct access and step-by-step control:
from read_google_sheet import GoogleSheetConfig
config = GoogleSheetConfig(
sheet_id="1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms",
sheet_name="Sheet1",
timeout=10,
)
result = config.to_lazyframe() # Result[pl.LazyFrame, Exception]
result = config.to_dataframe() # Result[pl.DataFrame, Exception]
url = config.create_url() # Result[str, Exception]
data = config.fetch_data() # Result[StringIO, Exception]
Exceptions
All exceptions inherit from GoogleSheetError:
| Exception | Raised when |
|---|---|
ConfigurationError |
Invalid sheet ID or empty sheet name |
SheetFetchError |
HTTP request fails or returns a non-200 status |
NetworkError |
Connection error or timeout |
SheetTransformError |
CSV parsing or LazyFrame collection fails |
ValidationError |
General validation failure |
Error Handling Patterns
Pattern 1: Match on result
from read_google_sheet import read_google_sheet, ConfigurationError, NetworkError
match read_google_sheet(sheet_id="...", sheet_name="Sheet1"):
case Ok(lf):
df = lf.collect()
case Err(ConfigurationError() as e):
print(f"Config problem: {e}")
case Err(NetworkError() as e):
print(f"Network problem: {e}")
case Err(e):
print(f"Unexpected error: {e}")
Pattern 2: Chain operations
import polars as pl
from polars_result import Ok
from read_google_sheet import read_google_sheet
result = (
read_google_sheet(sheet_id="...", sheet_name="Sheet1")
.map(lambda lf: lf.filter(pl.col("amount") > 0))
.map(lambda lf: lf.select("vessel", "service", "amount"))
.and_then(lambda lf: Ok(lf.collect()))
)
Pattern 3: Fallback to another sheet
result = (
read_google_sheet(sheet_id="...", sheet_name="live")
.or_else(lambda _: read_google_sheet(sheet_id="...", sheet_name="backup"))
.unwrap_or(pl.LazyFrame())
)
Pattern 4: Unwrap with default
lf = read_google_sheet(sheet_id="...", sheet_name="Sheet1").unwrap_or(pl.LazyFrame())
Usage in Marimo Notebooks
import marimo as mo
from polars_result import Ok, Err
from read_google_sheet import read_google_sheet
result = read_google_sheet(
sheet_id="1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms",
sheet_name="Sheet1",
as_dataframe=True,
)
match result:
case Ok(df):
mo.ui.table(df)
case Err(e):
mo.callout(mo.md(f"**Failed to load sheet:** {e}"), kind="danger")
How It Works
The package uses Google Sheets' public CSV export endpoint — no API key or OAuth required. The sheet must be set to "Anyone with the link can view".
The URL format used internally:
https://docs.google.com/spreadsheets/d/{sheet_id}/gviz/tq?tqx=out:csv&sheet={sheet_name}
Development
uv sync # install dependencies
uv run pytest # run tests
uv run pytest --cov=src/read_google_sheet --cov-report=html # with coverage
uv run ruff check src/ tests/ # lint
uv run ruff format src/ tests/ # format
uv run ty check # type check
Contributing
Contributions welcome — please open an issue or PR on GitHub.
License
MIT — see LICENSE for details.
Metadata
Release files for read-google-sheet 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| read_google_sheet-0.1.0.tar.gz | 36.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| read_google_sheet-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.3 kB
Release files / read_google_sheet-0.1.0.tar.gz
| Download URL | read_google_sheet-0.1.0.tar.gz |
|---|---|
| Size | 36.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3c7dce25de32419d6351a91d7a3314f96b19871973165719d8119736748f10a8
|
|
BLAKE2b-256 checksum How to use checksums |
b4d1d9db83b5e555d7a24e28ed165eb538e77db9844fca065bf050e52d3246e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / read_google_sheet-0.1.0-py3-none-any.whl
| Download URL | read_google_sheet-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9b7ece7bb6fb08fbda14cafb608a34a8fcb1ca793ede538cba3e34524bbaa656
|
|
BLAKE2b-256 checksum How to use checksums |
13bdb3525dfe7ed11d66480263f9f20a7bf753a856339d35891baa13086fc866
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|