Metadata-Version: 2.4
Name: toolsgdrivegsheet
Version: 0.1.1
Summary: Lightweight helpers for Google Drive and Google Sheets with unified credential resolution.
Author: MH
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: google-api-python-client>=2.0
Requires-Dist: google-auth-httplib2>=0.1
Requires-Dist: google-auth-oauthlib>=0.5
Requires-Dist: google-auth>=2.0
Dynamic: license-file

# toolsgdrivegsheet

Lightweight helpers for **Google Drive** and **Google Sheets** with unified credential resolution.

Credentials are resolved once and shared across both APIs — no duplicate file reads or token refreshes.

## Install

```bash
pip install toolsgdrivegsheet
```

## Quick start

```python
from toolsgdrivegsheet import get_services

drive, sheets = get_services(path_keyfile="~/key.json")
```

Or individually:

```python
from toolsgdrivegsheet import gdrive_get_service, gsheet_get_service

drive  = gdrive_get_service()
sheets = gsheet_get_service()
```

## Authentication

All service constructors (`gdrive_get_service`, `gsheet_get_service`, `get_services`) accept the same credential options. Resolution order:

1. `credentials` — pre-resolved credentials object (e.g. from `toolsbq` via `bq_client._credentials`)
2. `keyfile_json` — SA key as dict
3. `path_keyfile` — path to SA JSON file (supports `~` and `$HOME` expansion)
4. `GOOGLE_APPLICATION_CREDENTIALS` env var
5. Local RAM-ADC fast path (macOS ramdisk / Linux `/dev/shm`)
6. ADC fallback (Cloud Run metadata, `gcloud auth application-default login`, etc.)

```python
from toolsgdrivegsheet import gdrive_get_service

# ADC (default)
drive = gdrive_get_service()

# Service account file
drive = gdrive_get_service(path_keyfile="~/.config/gcloud/sa-keys/key.json")

# Service account info dict (e.g. from CI secret)
drive = gdrive_get_service(keyfile_json={"type": "service_account", "...": "..."})

# Reuse credentials from toolsbq
from toolsbq import bq_get_client
bq = bq_get_client(path_keyfile="~/key.json")
drive = gdrive_get_service(credentials=bq._credentials)
```

Note: The service account must have access to the target Drive folders and spreadsheets. Share them with the service account email.

## Credential reuse

`get_credentials()` is exposed for when you need the raw credentials object:

```python
from toolsgdrivegsheet import get_credentials, gdrive_get_service, gsheet_get_service

creds = get_credentials(path_keyfile="~/key.json")
drive  = gdrive_get_service(credentials=creds)    # no file re-read
sheets = gsheet_get_service(credentials=creds)     # no file re-read
```

Or use the convenience function:

```python
from toolsgdrivegsheet import get_services

drive, sheets = get_services(path_keyfile="~/key.json")
```

## Drive API

```python
from toolsgdrivegsheet import gdrive_get_service, list_files, download_file_to_disk, download_file_to_csv

drive = gdrive_get_service(path_keyfile="~/key.json")
```

### List files

```python
# All files (up to 200)
files = list_files(drive)

# CSV files in a specific folder, modified after a date
files = list_files(
    drive,
    q_filter="mimeType='text/csv' and trashed=False and '<FOLDER_ID>' in parents and modifiedTime > '2024-01-01'",
    limit_pull=50,
)

for f in files:
    print(f["name"], f["modifiedTime"], f["id"])
```

### Download files

```python
# To disk
download_file_to_disk(drive, file_id="abc123", filename_path="/tmp/report.csv")

# To CSV DictReader (in memory)
reader = download_file_to_csv(drive, file_id="abc123")
if reader:
    for row in reader:
        print(row)
```

### Drive API reference

| Function | Description |
|---|---|
| `gdrive_get_service(...)` | Build Drive v3 service object |
| `list_files(service, q_filter, fields, limit_pull, sort_order)` | List files with optional filtering/sorting |
| `download_file(service, file_id)` | Download file → `BytesIO` |
| `download_file_to_disk(service, file_id, filename_path)` | Download file → save to disk |
| `download_file_to_csv(service, file_id, decoding, delimiter)` | Download CSV → `DictReader` |

## Sheets API

```python
from toolsgdrivegsheet import gsheet_get_service, list_sheet_names, read_sheet, read_sheet_as_dicts

sheets = gsheet_get_service(path_keyfile="~/key.json")
spreadsheet_id = "your_spreadsheet_id"
```

### List sheet names

```python
names = list_sheet_names(sheets, spreadsheet_id)
print(names)  # ["Sheet1", "Sheet2", "Config"]
```

### Read a sheet

```python
# Raw rows (list of lists)
rows = read_sheet(sheets, spreadsheet_id, sheet_range="Sheet1!A1:Z100")

# As list of dicts (first row = headers)
data = read_sheet_as_dicts(sheets, spreadsheet_id, sheet_range="Sheet1")
for row in data:
    print(row)
```

### Read all sheets

```python
from toolsgdrivegsheet import read_all_sheets

all_data = read_all_sheets(sheets, spreadsheet_id)
for sheet_name, rows in all_data.items():
    print(f"{sheet_name}: {len(rows)} rows")
```

### Sheets: read-only vs. read-write

```python
# Read-only (default)
sheets = gsheet_get_service(readonly=True)

# Read-write (for updating cells)
sheets = gsheet_get_service(readonly=False)
```

### Sheets API reference

| Function | Description |
|---|---|
| `gsheet_get_service(readonly=True, ...)` | Build Sheets v4 service object |
| `list_sheet_names(service, spreadsheet_id)` | Get all tab names |
| `read_sheet(service, spreadsheet_id, sheet_range)` | Read range → list of lists |
| `read_sheet_as_dicts(service, spreadsheet_id, sheet_range)` | Read range → list of dicts (header row = keys) |
| `read_all_sheets(service, spreadsheet_id, sheet_range_data)` | Read all tabs → dict of sheet name → rows |

## Enable APIs

Make sure these APIs are enabled in your GCP project:

- **Drive API**: https://console.cloud.google.com/apis/library/drive.googleapis.com
- **Sheets API**: https://console.cloud.google.com/apis/library/sheets.googleapis.com

## Security notes

- Avoid committing service account keyfiles to git.
- Prefer `keyfile_json` sourced from a secure secret store (CI secrets, vault, etc.).

## Development

```bash
python -m pip install --upgrade build twine
python -m build
twine check dist/*
twine upload dist/*
```
