Skip to main content

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.

PyPI Python License: MIT CI


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_sheet and scan_google_sheet
  • Polars IO plugin for lazy evaluation
  • Structured exception hierarchy
  • Full test suite with pytest-httpx

License

MIT © 2025 Attica-oss

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scan_google_sheet-0.1.0.tar.gz (9.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scan_google_sheet-0.1.0-py3-none-any.whl (12.5 kB view details)

Uploaded Python 3

File details

Details for the file scan_google_sheet-0.1.0.tar.gz.

File metadata

  • Download URL: scan_google_sheet-0.1.0.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

Hashes for scan_google_sheet-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a5d37af0d3ad0ef9bc2892debb5a6bbeccd3e958282e2894f94eaa9ff49c45ec
MD5 410a10039ba9357436395076dbd5f18d
BLAKE2b-256 89aa528a644af7874e057b689fcf83f6a7824126403d46febf72690d2fbccdc5

See more details on using hashes here.

File details

Details for the file scan_google_sheet-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: scan_google_sheet-0.1.0-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

Hashes for scan_google_sheet-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 670092612e03dfc8af234481a244cb801a8bae8dfd988029c83b2fcfae648d86
MD5 3042e0997e2f88d243d80f67f5584d0d
BLAKE2b-256 48a766dea587dfc691fda2361a54319ca8461b46efe2bff24a66f4c13eaad756

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page