# windchill-rest

`windchill-rest` is a Python package that provides a lightweight, object‑oriented interface to **PTC Windchill’s REST API**. It abstracts common REST patterns and Windchill‑specific behaviors into Python classes, allowing scripts to interact with Windchill data without dealing directly with raw REST calls.

The library is designed for automation, integration, and scripting use cases where repeatable access to Windchill objects and workflows is required.

---

## Key Capabilities

- Authentication and session management
  - OAuth or basic authentication
- Automatic CSRF handling and token refresh
- Object‑oriented access to Windchill REST resources
- Support for common Windchill object types:
  - Parts, CAD Documents (EPMs), and Documents
  - Change objects (Problem Reports, Change Requests, Change Notices)
  - Users and Groups
- Lifecycle and workflow actions:
  - Create, update, delete
  - Check‑in / check‑out
  - Revise
  - Set lifecycle state
- Relationship management:
  - Part ↔ CAD document associations
  - Described‑by relationships
  - Attachments and primary content
- File upload and download support
- Transparent handling of paging and OData query options

---

## Installation

Install via pip:

```bash
pip install windchill-rest
````

***

## Authentication

Authentication is handled through the `WcSession` class. Both basic (username & password) and Oauth authentication is supported. 

### Basic Authentication

```python
from windchill_rest import *

wc_session = WcSession.basic(
    wc_base_url="https://your.windchill.server/Windchill",
    username="xxxxxx",
    password="yyyyyy"
)

wc_session.authenticate()
```

### OAuth Authentication

```python
from windchill_rest import *

wc_session = WcSession.oauth(
    wc_base_url="https://your.windchill.server/Windchill",
    auth_url="https://your.auth.server/authorize",
    token_url="https://your.auth.server/token",
    client_id="your-client-id",
    client_secret="your-client-secret",
    redirect_uri="http://your.redirect",
    scope="Windchill.Read"
)

wc_session.authenticate()
```

This will:

1.  Open a browser window for authorization.
2.  Prompt you to log in and approve the application.
3.  Redirect you to a URL.
4.  Ask you to paste the redirect URL back into the console.

After authentication:

*   Access tokens and refresh tokens are stored on the session
*   CSRF headers are retrieved automatically
*   Tokens are refreshed automatically as needed

> **Note (Windows users):**  
> If you encounter a `SSL: CERTIFICATE_VERIFY_FAILED` error during authentication, you may need to install the following package:
>
> ```bash
> pip install python-certifi-win32
> ```
>
> This ensures Python uses the Windows certificate store.

***

## Using the Framework

### Querying Objects

Objects are retrieved using `get_objects`, which returns a generator and transparently handles paging.

```python
parts = wc_session.get_objects(
    WcPart,
    filter_str="Number eq '12345'",
    select_str="Number,Name,Revision"
)

for part in parts:
    print(part.attrs["Number"], part.attrs["Name"])
```

Supported OData options include:

*   `$filter`
*   `$select`
*   `$orderby`
*   `$expand`

***

### Creating Objects

```python
attrs = {
    "@odata.type": "#PTC.ProdMgmt.Part",
    "Number": "12345",
    "Name": "Example Part",
    "View": "Design",
    "Context@odata.bind": "Containers('OR:wt.pdmlink.PDMLinkProduct:123456')"
}

part = wc_session.create_object(WcPart, attrs)
```

***

### Updating and Deleting Objects

```python
part.update({
    "Name": "Updated Part Name"
})

part.delete()
```

***

### Lifecycle and Check In/Out Actions

Objects that support lifecycle actions inherit from `WcWorkable`.

```python
part.checkout()
part.checkin()

part.revise("B")
part.set_state("RELEASED")
```

***

### Navigating Relationships

Related objects can be retrieved using navigation properties.

```python
# Get CAD documents associated to a part
assocs = part.get_assoc_epms()

for assoc in assocs:
    print(assoc.attrs)
```

***

### Managing Content

Documents support primary content and attachments.

```python
doc = next(wc_session.get_objects(WcDoc, filter_str="Number eq 'DOC-001'"))

# Download primary content
primary = doc.get_prim_content()
file_bytes = primary.download_file()

# Add or replace primary content
doc.add_prim_content("file.pdf", file_bytes)

# Add attachment
doc.add_attachment("attachment.txt", b"example content")
```

***

## Architecture Overview

The package is structured around a small set of core components:

*   **WcSession**  
    Handles authentication, REST calls, paging, headers, and token refresh.

*   **WcObj**  
    Base class providing CRUD operations and navigation of related objects.

*   **WcWorkable**  
    Extends `WcObj` with lifecycle and check in/out behavior.

*   **Domain Objects**  
    Windchill concepts such as Parts, Documents, CAD Documents, Change objects,
    Users, and Groups are modeled as Python classes with domain‑specific behavior.

This design allows scripts to operate at the object level rather than managing
REST endpoints directly.

***

## Notes and Limitations

*   Some functionality relies on Windchill REST endpoints that may not be available
    in all environments or may require server‑side configuration.
*   File upload logic is intentionally strict due to Windchill API requirements.
*   This package is not an official PTC SDK and is provided as‑is.

***

## Disclaimer

This project is not affiliated with or endorsed by PTC.  
Windchill is a registered trademark of PTC Inc.

```
