Skip to main content

markdown

pydantic-gsheets

[![PyPI](https://img.shields.io/pypi/v/pydantic-gsheets)](https://pypi.org/project/pydantic-gsheets/)

License: MIT Docs

A Python library for sending and receiving data from Google Sheets using Pydantic models.

With pydantic-gsheets, each row in a Google Sheet maps to a strongly-typed Pydantic model. You can read rows as validated objects and write updates back seamlessly.

Features

  • Declarative column mapping (GSIndex)
  • Required fields (GSRequired)
  • Custom parsing (GSParse)
  • Number/date/time formatting (GSFormat)
  • Read-only columns (GSReadonly)
  • Smart Chips: People and Drive file rich links (experimental)
  • Bulk read / bulk write helpers

📘 Full documentation: pydantic-gsheets API reference

💡 Beginner friendly: you only need basic Python and a Google account.


Installation

Python 3.10+ is recommended.

pip install pydantic-gsheets

If you’re using a virtual environment:

python -m venv .venv
.venv\Scripts\activate  # Windows
source .venv/bin/activate  # macOS/Linux
pip install pydantic-gsheets

Google Cloud Setup (One-Time)

  1. Go to Google Cloud Console and create or select a project.

  2. Enable these APIs:

    • Google Sheets API
    • Google Drive API (required for Drive file smart chips or file metadata)
  3. Configure an OAuth consent screen (choose External for testing).

  4. Create OAuth client credentials of type Desktop and download the JSON (e.g., client_secret.json).

  5. Decide on a token cache location (e.g., .tokens/google.json). This will be created automatically on first authentication.


Quick Start

from typing import Annotated
from pydantic_gsheets import (
    AuthConfig, AuthMethod, get_sheets_service,
    GoogleWorkSheet, SheetRow,
    GSIndex, GSRequired
)

# 1. Authenticate (first run opens a browser for consent)
svc = get_sheets_service(AuthConfig(
    method=AuthMethod.USER_OAUTH,
    client_secrets_file="client_secret.json",
    token_cache_file=".tokens/google.json",
))

# 2. Define a row model
class UserRow(SheetRow):
    name: Annotated[str, GSRequired()]
    email: Annotated[str, GSRequired()]
    age: Annotated[int]

# 3. Bind to a worksheet (tab)
sheet = GoogleWorkSheet(
    model=UserRow,
    service=svc,
    spreadsheet_id="<SPREADSHEET_ID>",  # replace with your sheet ID
    sheet_name="Users",   # tab title
    start_row=2           # row 1 is headers
)

# 4. Read rows
for row in sheet.rows():
    print(row.name, row.email)

# 5. Append a new row
new_user = UserRow(name="Alice", email="alice@example.com", age=30)
sheet.saveRow(new_user)

Core Concepts

Marker Purpose
GSIndex(i) Zero-based column index relative to start_column.
GSRequired() Field must not be empty on read or write.
GSParse(func) Apply func(raw_value) before validation.
GSFormat(type, pattern?) Assigns Google Sheets number/date format.
GSReadonly() Value is read but never written back.
GS_SMARTCHIP(fmt, smartchips=[...]) Define Smart Chip format placeholders (experimental).

Lifecycle

  • Read: Cells → optional parse → Pydantic validation → SheetRow instance
  • Modify: Update attributes in Python
  • Write: Use save() (single) or saveRows([...]) (bulk)

Examples

Formatting Dates

from datetime import datetime
from typing import Annotated
from pydantic_gsheets import GSFormat, GSIndex, GSRequired, SheetRow

class LogRow(SheetRow):
    event: Annotated[str, GSIndex(0), GSRequired()]
    created_at: Annotated[
        datetime,
        GSIndex(1),
        GSRequired(),
        GSFormat("DATE_TIME", "dd-MM-yyyy HH:mm")
    ]

Custom Parsing

def to_int_or_zero(value: str) -> int:
    return int(value) if value.strip().isdigit() else 0

class ParsedRow(SheetRow):
    raw_number: Annotated[int, GSIndex(0), GSParse(to_int_or_zero)]

Read-only Columns

class Employee(SheetRow):
    id: Annotated[int, GSIndex(0), GSRequired(), GSReadonly()]
    name: Annotated[str, GSIndex(1), GSRequired()]

Bulk Writes

rows = [UserRow(name=f"User {i}", email=f"u{i}@ex.com", age=20+i) for i in range(5)]
sheet.saveRows(rows)

Smart Chips (Experimental)

Smart Chips let you mix plain text with structured entities (people and Drive file links).

⚠️ Only Google Drive file links can currently be written as chips. Other service links (YouTube, Calendar, etc.) are read-only.

from typing import Annotated
from pydantic_gsheets.types import (
    smartChips, GS_SMARTCHIP,
    peopleSmartChip, fileSmartChip
)

class OwnershipRow(SheetRow):
    ownership: Annotated[
        smartChips,
        GS_SMARTCHIP(
            "@ owner of @",
            smartchips=[peopleSmartChip, fileSmartChip]
        ),
        GSIndex(0), GSRequired()
    ]

Creating Sheets Programmatically

sheet = GoogleWorkSheet.create_sheet(
    model=UserRow,
    service=svc,
    spreadsheet_id="<SPREADSHEET_ID>",
    sheet_name="Users",
    add_column_headers=True,
    skip_if_exists=True
)

Error Handling

  • RequiredValueError → Raised when a GSRequired field is blank.
  • Pydantic validation errors → Raised if a cell’s value cannot be coerced to the annotated type.

Tips for Beginners

  • Add client_secret.json and .tokens/ to your .gitignore.
  • Start with a simple sheet (2–3 columns) before scaling up.
  • If writes seem to “do nothing,” check for GSReadonly or missing GSIndex.
  • Use refresh=True when you need the latest remote state.

FAQ

Q: Do I need the Drive API enabled? A: Only if you use smart chips involving Drive files or file helpers.

Q: Can I append rows without indices? A: Yes. Un-indexed fields follow declaration order. Explicit indices reserve/skip columns.

Q: How do I format currency? A: Use GSFormat("CURRENCY", "€#,##0.00").


Contributing

Contributions are welcome! 🎉

  1. Fork & clone
  2. Create a virtual environment and install dev dependencies (pip install -e ".[dev]")
  3. Add or adjust tests in tests/
  4. Open an issue or a PR with a clear description

Roadmap

See ROADMAP.md


Minimal End-to-End Script

from typing import Annotated
from pydantic_gsheets import (
    AuthConfig, AuthMethod, get_sheets_service,
    GoogleWorkSheet, SheetRow, GSIndex, GSRequired
)

svc = get_sheets_service(AuthConfig(
    method=AuthMethod.USER_OAUTH,
    client_secrets_file="client_secret.json",
    token_cache_file=".tokens/google.json",
))

class Demo(SheetRow):
    title: Annotated[str, GSIndex(0), GSRequired()]
    views: Annotated[int, GSIndex(1)]

sheet = GoogleWorkSheet(Demo, svc, "<SPREADSHEET_ID>", "Demo", start_row=2)

# Append
items = [Demo(title=f"Post {i}", views=i*10) for i in range(3)]
sheet.saveRows(items)

# Read back
for row in sheet.rows(refresh=True):
    print(row.title, row.views)

License

MIT License © 2025 Youssef Benhammouda

Metadata

Release files for pydantic-gsheets 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pydantic-gsheets 1.0.0
File Size Uploaded
pydantic_gsheets-1.0.0.tar.gz 34.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pydantic-gsheets 1.0.0
File Interpreter ABI Platform
pydantic_gsheets-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 74.0 kB

Release files / pydantic_gsheets-1.0.0.tar.gz

Download URL pydantic_gsheets-1.0.0.tar.gz
Size 34.2 kB
Tags Source
SHA-256 checksum
How to use checksums
fe90e496561ed2b268c1eb4c4d5bb982ed5593c46ce188dddcf59d138edfc028
BLAKE2b-256 checksum
How to use checksums
15acefff6e23132c669e455acf3f0a0297a4aa80338b899b711a8baa8e83b28e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / pydantic_gsheets-1.0.0-py3-none-any.whl

Download URL pydantic_gsheets-1.0.0-py3-none-any.whl
Size 39.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fc3c418a7d88ccd964d31fd0d2f81ad5b6460585c096db50628f70580cbcc9ed
BLAKE2b-256 checksum
How to use checksums
77ef43a06718c68522c7d971225dd657440f25eeff7f6e2236fed196ee74e6a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page