Read public Google Sheets into Polars LazyFrames — no auth required
Project description
read-sheet
Read public Google Sheets into Polars DataFrames and LazyFrames — no auth, no service accounts, no API keys.
Requirements
- Python ≥ 3.13
- The spreadsheet must be set to Anyone with the link can view
Installation
pip install scan-google-sheet
# or
uv add scan-google-sheet
Quick start
from scan_google_sheet import read_google_sheet, scan_google_sheet
Eager — returns a DataFrame immediately:
df = read_google_sheet("Sheet1", sheet_id="1BxiMVs0XRA5nFMdKvBdBZjgm...")
Lazy — returns a LazyFrame, participates in Polars query optimisation:
lf = scan_google_sheet("Sheet1", sheet_id="1BxiMVs0XRA5nFMdKvBdBZjgm...")
df = (
lf
.filter(pl.col("year") == 2025)
.select("vessel", "amount")
.collect()
)
You can also pass a full Google Sheets URL instead of a bare sheet ID:
df = read_google_sheet(
"Sheet1",
url="https://docs.google.com/spreadsheets/d/1BxiMVs0.../edit#gid=0",
)
API
read_google_sheet
def read_google_sheet(
sheet_name: str,
sheet_id: str | None = None,
url: str | None = None,
*,
timeout: int = 10,
parse_dates: bool = True,
) -> pl.DataFrame
Fetches the sheet and returns a collected DataFrame. Use this when you want the data immediately and do not need lazy evaluation.
scan_google_sheet
def scan_google_sheet(
sheet_name: str,
sheet_id: str | None = None,
url: str | None = None,
*,
timeout: int = 10,
parse_dates: bool = True,
batch_size: int = 1_000,
) -> pl.LazyFrame
Returns a LazyFrame registered via the Polars IO plugin API. Projection pushdown, predicate pushdown, head(), and streaming are all supported.
Note: Google Sheets does not support partial HTTP reads. The full sheet is always downloaded in one request. Pushdowns reduce processing cost, not network cost.
Parameters shared by both functions:
| Parameter | Type | Default | Description |
|---|---|---|---|
sheet_name |
str |
— | Tab name as shown in Google Sheets |
sheet_id |
str | None |
None |
Spreadsheet ID from the URL |
url |
str | None |
None |
Full Google Sheets URL (ID extracted automatically) |
timeout |
int |
10 |
HTTP timeout in seconds |
parse_dates |
bool |
True |
Attempt automatic date/datetime parsing |
Provide either sheet_id or url, not both.
URL utilities
from scan_google_sheet import extract_sheet_id, build_gviz_url, from_url
# Extract the sheet ID from any Google Sheets URL
sheet_id = extract_sheet_id("https://docs.google.com/spreadsheets/d/ABC123/edit")
# "ABC123"
# Build a gviz CSV export URL from a sheet ID and tab name
url = build_gviz_url("ABC123", "Sheet1")
# "https://docs.google.com/spreadsheets/d/ABC123/gviz/tq?tqx=out:csv&sheet=Sheet1"
# Build a gviz URL directly from a full Google Sheets URL
url = from_url("https://docs.google.com/spreadsheets/d/ABC123/edit", "Sheet1")
Error handling
All exceptions inherit from ReadSheetError, so you can catch everything with one handler or branch on specific types:
from scan_google_sheet import (
read_google_sheet,
ReadSheetError,
SheetFetchError,
SheetURLError,
SheetParseError,
NetworkError,
ConfigurationError,
)
try:
df = read_google_sheet("Sheet1", sheet_id="...")
except ReadSheetError as e:
match e:
case SheetFetchError() if e.is_auth_error:
print("Make the sheet public (Share → Anyone with the link)")
case SheetFetchError() if e.is_not_found:
print(f"Sheet not found — check the ID: {e.url}")
case NetworkError():
print(f"No connection: {e.cause}")
case SheetURLError(raw=r):
print(f"Could not parse URL: {r!r}")
case SheetParseError():
print(f"CSV parse failed: {e.cause}")
case ConfigurationError():
print(str(e))
Exception hierarchy
ReadSheetError
├── SheetURLError malformed URL or unextractable sheet ID (.raw)
├── SheetFetchError non-200 HTTP response (.url, .status_code)
│ (.is_auth_error, .is_not_found)
├── SheetParseError CSV or Polars parsing failure (.column)
├── NetworkError transport failure, no response received (.url)
└── ConfigurationError invalid argument combination
Making your sheet public
In Google Sheets: Share → Change to Anyone with the link → Viewer → Done.
The export URL used by this library (gviz/tq?tqx=out:csv) requires the sheet to be publicly readable. No data is ever written.
How it works
Google Sheets URL / ID
│
▼
build_gviz_url() constructs the CSV export URL
│
▼
fetch_raw() httpx GET with follow_redirects=True
│
▼
pl.scan_csv() parsed into a Polars LazyFrame
│
▼
register_io_source() registered as a Polars IO plugin
│
▼
LazyFrame / DataFrame ready for your pipeline
Development
git clone https://github.com/Attica-oss/scan_google_sheet
cd scan_google_sheet
uv sync --group dev
uv run pytest
Lint and format:
uv run ruff check src/ tests/
uv run ruff format src/ tests/
uv run ty check src/
Changelog
0.1.0 (2025)
- Initial release
read_google_sheetandscan_google_sheet- Polars IO plugin for lazy evaluation
- Structured exception hierarchy
- Full test suite with
pytest-httpx
License
MIT © 2025 Attica-oss
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scan_google_sheet-0.1.1.tar.gz.
File metadata
- Download URL: scan_google_sheet-0.1.1.tar.gz
- Upload date:
- Size: 9.3 kB
- Tags: Source
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3c13e1609723432df3ce0d5a07007573b96271cbfee14c9efa08e21f5713860
|
|
| MD5 |
29418aed529da63360babc7f3c8d798e
|
|
| BLAKE2b-256 |
bb2aa7469c2e73d2f080125039d3bab11e112a0e8914cd6f386cc536423df2b8
|
File details
Details for the file scan_google_sheet-0.1.1-py3-none-any.whl.
File metadata
- Download URL: scan_google_sheet-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.5 kB
- Tags: Python 3
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6421781cf0ec2b0688444f41ae299e0ed766268695bd762570b9a94ae321f32
|
|
| MD5 |
97540dd5a6a7a1bbf99016a28964b9c7
|
|
| BLAKE2b-256 |
9c2f5c70ab3fa826e4108305e04524b9074b2e95c79681d0aa41d27de4dfc93a
|