Metadata-Version: 2.4
Name: quickbase-api
Version: 0.1.0
Summary: A simple Python wrapper for the Quickbase API
Project-URL: Homepage, https://github.com/tbrezler/quickbase-api
Project-URL: Issues, https://github.com/tbrezler/quickbase-api/issues
Project-URL: Documentation, https://github.com/tbrezler/quickbase-api#readme
Author-email: Tyler Brezler <tbrezler@gmail.com>
License: MIT
License-File: LICENSE.txt
Keywords: api,database,quickbase,rest,wrapper
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: requests>=2.25.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: responses>=0.20; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Description-Content-Type: text/markdown

# quickbase-api

A simple Python wrapper for the [Quickbase API](https://developer.quickbase.com/).

[![PyPI version](https://badge.fury.io/py/quickbase-api.svg)](https://pypi.org/project/quickbase-api/)
[![Python versions](https://img.shields.io/pypi/pyversions/quickbase-api.svg)](https://pypi.org/project/quickbase-api/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Installation

```bash
pip install quickbase-api
```

## Quick Start

```python
import quickbase_api

# Option 1: Pass credentials directly
client = quickbase_api.client(
    realm="mycompany.quickbase.com",
    user_token="your-user-token",
)

# Option 2: Use environment variables
#   export QUICKBASE_REALM=mycompany.quickbase.com
#   export QUICKBASE_USER_TOKEN=your-user-token
client = quickbase_api.client()

# Query records from a table
records = client.query_for_data(
    table_id="bqrg4xyza",
    select=[3, 6, 7],
    where="{6.EX.'Active'}",
)
```

## Authentication

This library uses [Quickbase user tokens](https://developer.quickbase.com/auth) for
authentication. You can pass your credentials directly or set environment variables:

| Environment Variable     | Description                                            |
|--------------------------|--------------------------------------------------------|
| `QUICKBASE_REALM`        | Your Quickbase realm (e.g., `mycompany.quickbase.com`) |
| `QUICKBASE_USER_TOKEN`   | Your Quickbase user token                              |

> **Security note:** Never commit tokens to source control. Use environment variables
> or a secrets manager.

## Usage

### Apps

```python
# Create an app
app_id = client.create_app(
    name="My App",
    description="An example app",
    assign_token=True,
)

# Get app metadata
app = client.get_app(app_id)

# Delete an app
client.delete_app("My App", app_id)
```

### Tables

```python
# Create a table
table_id = client.create_table(app_id, {
    "name": "Customers",
    "description": "Customer records",
})

# List all tables in an app
tables = client.get_tables(app_id)

# Find a table ID by name
table_id = client.get_table_id(app_id, "Customers")

# Delete a table
client.delete_table(app_id, table_id)
```

### Fields

```python
# Create a field
client.create_field(table_id, {
    "label": "Full Name",
    "fieldType": "text",
})

# Create multiple fields at once
results = client.create_fields(table_id, [
    {"label": "Email", "fieldType": "email"},
    {"label": "Age", "fieldType": "numeric"},
    {"label": "Active", "fieldType": "checkbox"},
])
print(f"Created: {len(results['succeeded'])}, Failed: {len(results['failed'])}")

# List all fields in a table
fields = client.get_table_fields(table_id)

# Find a field ID by label
field_id = client.get_field_id(table_id, "Full Name")

# Get a mapping of all field labels to IDs
field_map = client.get_field_label_id_map(table_id)
# {"Full Name": "6", "Email": "7", "Age": "8", "Active": "9"}

# Set a key field (uses legacy API)
client.set_key_field(table_id, field_id)

# Mark a field as required
client.set_required_field(table_id, field_id)
```

### Records

```python
# Upsert (insert or update) records
result = client.upsert_records(table_id, [
    {
        "6": {"value": "Jane Smith"},
        "7": {"value": "jane@example.com"},
        "8": {"value": 32},
    },
    {
        "6": {"value": "Bob Jones"},
        "7": {"value": "bob@example.com"},
        "8": {"value": 45},
    },
])
print(f"Created: {result['created']}, Updated: {result['updated']}")

# Check for partial failures
if result["errored"] > 0:
    print(f"Errors: {result['errored_details']}")

# Query for records
records = client.query_for_data(
    table_id=table_id,
    select=[6, 7, 8],
    where="{8.GT.30}",
    sort_by=[{"fieldId": 6, "order": "ASC"}],
    options={"skip": 0, "top": 100},
)

# Delete records
deleted = client.delete_records(table_id, where="{8.LT.18}")
print(f"Deleted {deleted} records")
```

### Reports

```python
# List all reports for a table
reports = client.get_reports(table_id)

# Get a specific report
report = client.get_report(table_id, report_id="1")

# Run a report
results = client.run_report(table_id, report_id="1", skip=0, top=100)
```

## Error Handling

The library raises specific exceptions that you can catch and handle:

```python
from quickbase_api import QuickbaseAPIError, QuickbaseNotFoundError

# Handle API errors
try:
    app = client.get_app("invalid-id")
except QuickbaseAPIError as e:
    print(f"API error {e.status_code}: {e.response_body}")

# Handle not-found lookups
try:
    table_id = client.get_table_id(app_id, "Nonexistent Table")
except QuickbaseNotFoundError as e:
    print(f"Not found: {e}")
```

Exception hierarchy:

```
QuickbaseError              # Base exception
├── QuickbaseAPIError       # HTTP errors from the API
└── QuickbaseNotFoundError  # Resource not found in lookup methods
```

## Logging

This library uses Python's built-in `logging` module. To see log output,
configure logging in your application:

```python
import logging

# See all quickbase-api log messages
logging.basicConfig(level=logging.INFO)

# Or configure just the quickbase_api logger
logging.getLogger("quickbase_api").setLevel(logging.DEBUG)
```

## Configuration

### Retry Behavior

The library automatically retries failed requests up to 5 times with
exponential backoff for the following HTTP status codes:

- `429` — Rate limited
- `502` — Bad gateway
- `503` — Service unavailable
- `504` — Gateway timeout

## Requirements

- Python 3.9+
- [requests](https://requests.readthedocs.io/) >= 2.25.0

## License

This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.