# autodesk-acc - Autodesk Construction Cloud SDK for Python

A Python SDK providing a [Fluent API](https://dzone.com/articles/java-fluent-api) for the [Autodesk Construction Cloud (ACC)](https://aps.autodesk.com/en/docs/acc/v1/overview/) APIs, generated from the official OpenAPI specifications using [Microsoft Kiota](https://learn.microsoft.com/en-us/openapi/kiota/overview).

## Installation

```bash
pip install adsk-platform-acc
```

## Quick Start

```python
from autodesk_acc import ACCClient

# Provide an async function that returns the access token
async def get_access_token() -> str:
    return "YOUR_ACCESS_TOKEN"

# Initialize the ACC client
acc_client = ACCClient(get_access_token)
```

### Using with 2-Legged Authentication

For server-to-server communication using client credentials (2-legged OAuth), use the companion [`adsk-platform-authentication`](https://pypi.org/project/adsk-platform-authentication/) package:

```bash
pip install adsk-platform-authentication
```

```python
import os
from autodesk_authentication import AuthenticationClient
from autodesk_acc import ACCClient

client_id = os.environ["APS_CLIENT_ID"]
client_secret = os.environ["APS_CLIENT_SECRET"]

auth_client = AuthenticationClient()
token = await auth_client.helper.get_two_legged_token(
    client_id,
    client_secret,
    scopes=["data:read", "data:write", "account:read"],
)

acc_client = ACCClient(lambda: token.access_token)
```

## Usage Examples

### Get Issues

```python
# Get issues for a project
issues = await acc_client.issues.projects[project_id].issues.get()

for issue in issues.results or []:
    print(f"Issue: {issue.title} - Status: {issue.status}")
```

### Get Clash Results

```python
# Get clash test results
clash_tests = await acc_client.clash.containers[container_id].clash.tests.get()
```

### Get Project Files

```python
# Get files in a folder
files = await acc_client.files.projects[project_id].folders[folder_id].contents.get()
```

### Get RFIs

```python
# Get RFIs for a project
rfis = await acc_client.rfis.projects[project_id].rfis.get()
```

### Using the `.api` Property

All endpoints are available through the `acc_client.api` property, which mirrors the full URL path. You can always use `.api` instead of (or in addition to) the shortcut properties:

```python
# These two calls are exactly equivalent:
issues = await acc_client.issues.projects[project_id].issues.get()               # shortcut
issues = await acc_client.api.construction.issues.v1.projects[project_id].issues.get()  # full path via .api
```

## Custom HTTP Client

You can provide your own `httpx.AsyncClient` instance for advanced scenarios:

```python
import httpx

http_client = httpx.AsyncClient(timeout=60.0)
# Configure your client...

acc_client = ACCClient(get_access_token, http_client=http_client)
```

## Rate Limiting

The SDK handles API rate limits automatically thanks to the built-in retry handler provided by the [Kiota HTTP client](https://learn.microsoft.com/en-us/openapi/kiota/middleware). When the API returns a `429 Too Many Requests` response, the SDK will:

- Automatically retry the request with exponential backoff
- Respect the `Retry-After` header returned by the API
- Retry up to a configurable number of times before failing

This means you don't need to implement custom retry logic in your application — the SDK handles transient failures and rate limiting transparently.

## Error Handling

The SDK uses Kiota's built-in error handling. API errors are raised as exceptions that you can catch:

```python
from kiota_abstractions.api_error import APIError

try:
    issues = await acc_client.issues.projects[project_id].issues.get()
except APIError as e:
    print(f"Request failed: {e.message}")
    print(f"Status code: {e.response_status_code}")
```

## API Structure

This SDK provides access to multiple ACC API endpoints through a unified client. Every endpoint is accessible via the `acc_client.api` property, which exposes the full generated API tree. For convenience, shortcut properties are also available on the client to skip the common path prefix — but they are **entirely optional**.

| API | Endpoint Path | Shortcut | Full `.api` equivalent |
|-----|---------------|----------|------------------------|
| **Accounts** | `/hq/v1/accounts/*` | `acc_client.accounts` | `acc_client.api.hq.v1.accounts` |
| **Admin** | `/construction/admin/v1/*` | `acc_client.admin` | `acc_client.api.construction.admin.v1` |
| **Assets** | `/construction/assets/*` | `acc_client.assets` | `acc_client.api.construction.assets` |
| **AutoSpecs** | `/construction/autospecs/v1/*` | `acc_client.auto_specs` | `acc_client.api.construction.autospecs.v1` |
| **Clash** | `/bim360/clash/v3/*` | `acc_client.clash` | `acc_client.api.bim360.clash.v3` |
| **Cost** | `/cost/v1/*` | `acc_client.cost` | `acc_client.api.cost.v1` |
| **Data Connector** | `/dataconnector/v1/*` | `acc_client.data_connector` | `acc_client.api.data_connector.v1` |
| **Docs** | `/bim360/docs/v1/*` | `acc_client.docs` | `acc_client.api.bim360.docs.v1` |
| **Files** | `/construction/files/v1/*` | `acc_client.files` | `acc_client.api.construction.files.v1` |
| **Forms** | `/construction/forms/v1/*` | `acc_client.forms` | `acc_client.api.construction.forms.v1` |
| **Index** | `/construction/index/v2/*` | `acc_client.index` | `acc_client.api.construction.index.v2` |
| **Issues** | `/construction/issues/v1/*` | `acc_client.issues` | `acc_client.api.construction.issues.v1` |
| **Locations** | `/construction/locations/v2/*` | `acc_client.locations` | `acc_client.api.construction.locations.v2` |
| **ModelSet** | `/bim360/modelset/v3/*` | `acc_client.model_set` | `acc_client.api.bim360.modelset.v3` |
| **Packages** | `/construction/packages/v1/*` | `acc_client.packages` | `acc_client.api.construction.packages.v1` |
| **Photos** | `/construction/photos/v1/*` | `acc_client.photos` | `acc_client.api.construction.photos.v1` |
| **RCM** | `/construction/rcm/v1/*` | `acc_client.rcm` | `acc_client.api.construction.rcm.v1` |
| **Relationships** | `/bim360/relationship/v2/*` | `acc_client.relationships` | `acc_client.api.bim360.relationship.v2` |
| **Reviews** | `/construction/reviews/v1/*` | `acc_client.reviews` | `acc_client.api.construction.reviews.v1` |
| **RFIs** | `/construction/rfis/v3/*` | `acc_client.rfis` | `acc_client.api.construction.rfis.v3` |
| **Sheets** | `/construction/sheets/v1/*` | `acc_client.sheets` | `acc_client.api.construction.sheets.v1` |
| **Submittals** | `/construction/submittals/v2/*` | `acc_client.submittals` | `acc_client.api.construction.submittals.v2` |
| **Takeoff** | `/construction/takeoff/v1/*` | `acc_client.takeoff` | `acc_client.api.construction.takeoff.v1` |
| **Transmittals** | `/construction/transmittals/v1/*` | `acc_client.transmittals` | `acc_client.api.construction.transmittals.v1` |

> **Note:** You never need to use the shortcut properties. They simply save a few keystrokes by resolving the common path prefix for you. The `acc_client.api` property gives you access to the complete API surface — including any endpoints that may not have a dedicated shortcut.

## Requirements

- Python 3.10 or later
- Valid Autodesk Platform Services (APS) access token with appropriate scopes

### Dependencies

- `microsoft-kiota-abstractions`
- `microsoft-kiota-http`
- `microsoft-kiota-serialization-json`
- `microsoft-kiota-serialization-text`
- `microsoft-kiota-serialization-form`
- `microsoft-kiota-serialization-multipart`
- `httpx`

## Documentation

- [ACC API Documentation](https://aps.autodesk.com/en/docs/acc/v1/overview/)
- [Autodesk Platform Services](https://aps.autodesk.com/)
- [Microsoft Kiota Documentation](https://learn.microsoft.com/en-us/openapi/kiota/overview)

## License

This project is licensed under the MIT License.
