Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .codegen.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "engineHash": "f9e2519", "specHash": "ccdb456", "version": "4.3.0" }
{ "engineHash": "b181eba", "specHash": "ccdb456", "version": "4.3.0" }
2 changes: 1 addition & 1 deletion docs/box_sdk_gen/ai.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ See the endpoint docs at
<!-- sample post_ai_extract_structured -->

```python
client.ai.create_ai_extract_structured([AiItemBase(id=file.id)], fields=[CreateAiExtractStructuredFields(key='firstName', display_name='First name', description='Person first name', prompt='What is the your first name?', type='string'), CreateAiExtractStructuredFields(key='lastName', display_name='Last name', description='Person last name', prompt='What is the your last name?', type='string'), CreateAiExtractStructuredFields(key='dateOfBirth', display_name='Birth date', description='Person date of birth', prompt='What is the date of your birth?', type='date'), CreateAiExtractStructuredFields(key='age', display_name='Age', description='Person age', prompt='How old are you?', type='float'), CreateAiExtractStructuredFields(key='hobby', display_name='Hobby', description='Person hobby', prompt='What is your hobby?', type='multiSelect', options=[CreateAiExtractStructuredFieldsOptionsField(key='guitar'), CreateAiExtractStructuredFieldsOptionsField(key='books')])], ai_agent=ai_extract_structured_agent_basic_text_config)
client.ai.create_ai_extract_structured([AiItemBase(id=file.id)], fields=[CreateAiExtractStructuredFields(key='firstName', display_name='First name', description='Person first name', prompt='What is the your first name?', type='string'), CreateAiExtractStructuredFields(key='lastName', display_name='Last name', description='Person last name', prompt='What is the your last name?', type='string'), CreateAiExtractStructuredFields(key='dateOfBirth', display_name='Birth date', description='Person date of birth', prompt='What is the date of your birth?', type='date'), CreateAiExtractStructuredFields(key='age', display_name='Age', description='Person age', prompt='How old are you?', type='float'), CreateAiExtractStructuredFields(key='hobby', display_name='Hobby', description='Person hobby', prompt='What is your hobby?', type='multiSelect', options=[CreateAiExtractStructuredFieldsOptionsField(key='guitar'), CreateAiExtractStructuredFieldsOptionsField(key='books')])], include_confidence_score=True, ai_agent=ai_extract_structured_agent_basic_text_config)
```

### Arguments
Expand Down
35 changes: 22 additions & 13 deletions docs/config-sharing-implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ This document describes the implementation of configuration sharing between the

<!-- END doctoc generated TOC please keep comment here to allow auto update -->


## Overview

The configuration sharing feature allows developers to seamlessly migrate from the legacy SDK to the generated SDK by automatically extracting and converting authentication and network configuration from a legacy client to a generated client.
Expand All @@ -38,11 +37,13 @@ The configuration sharing feature allows developers to seamlessly migrate from t
The `LegacyTokenStorageAdapter` class bridges the gap between legacy OAuth2 token storage mechanisms (callbacks) and the generated SDK's `TokenStorage` interface.

**Key Features:**

- Converts legacy token format (access_token, refresh_token tuple) to generated SDK `AccessToken` objects
- Supports both read and write operations
- Handles token storage callbacks from legacy OAuth2 implementations

**Example:**

```python
from boxsdk.auth.oauth2 import OAuth2
from boxsdk.util.token_storage_adapter import LegacyTokenStorageAdapter
Expand Down Expand Up @@ -86,6 +87,7 @@ Three new methods have been added to the `Client` class in `boxsdk/client/client
Creates a fully configured generated SDK client from the legacy client. This is the main convenience method that combines `get_sdk_gen_authentication()` and `get_sdk_gen_network_session()`.

**Parameters:**

- `auth_options` (optional): Dictionary with authentication options
- `token_storage`: Custom `TokenStorage` instance
- `network_options` (optional): Dictionary with network options
Expand All @@ -95,9 +97,11 @@ Creates a fully configured generated SDK client from the legacy client. This is
- `additional_headers`: Dictionary of additional HTTP headers

**Returns:**

- `BoxClient` instance from `box_sdk_gen`, fully configured with shared settings

**Example:**

```python
from boxsdk import Client
from boxsdk.auth import OAuth2
Expand All @@ -122,18 +126,22 @@ legacy_user = legacy_client.user().get()
Extracts authentication configuration from the legacy client and converts it to a generated SDK `Authentication` object.

**Supported Authentication Types:**

- `DeveloperTokenAuth` → `BoxDeveloperTokenAuth`
- `OAuth2` → `BoxOAuth`
- `JWTAuth` → `BoxJWTAuth`
- `CCGAuth` → `BoxCCGAuth`

**Parameters:**

- `token_storage` (optional): Custom `TokenStorage` instance. If not provided, an adapter will be created to bridge legacy token storage.

**Returns:**

- `Authentication` object compatible with `box_sdk_gen`

**Example:**

```python
from boxsdk import Client
from boxsdk.auth import OAuth2
Expand All @@ -153,21 +161,25 @@ gen_client = BoxClient(auth=gen_auth)
Extracts network configuration from the legacy client and converts it to a generated SDK `NetworkSession` object.

**Parameters:**

- `network_client` (optional): Custom `NetworkClient` instance
- `retry_strategy` (optional): Custom `RetryStrategy` instance
- `data_sanitizer` (optional): Custom `DataSanitizer` instance
- `additional_headers` (optional): Dictionary of additional HTTP headers

**Returns:**

- `NetworkSession` object compatible with `box_sdk_gen`

**Configuration Mapping:**

- Base URLs: Extracted from `API` config
- Proxy settings: Extracted from `Proxy` config
- Retry strategy: Extracted from `API.MAX_RETRY_ATTEMPTS` and session retry settings
- Custom headers: Merged from session default headers and additional headers

**Example:**

```python
from boxsdk import Client
from box_sdk_gen.client import BoxClient
Expand Down Expand Up @@ -205,10 +217,7 @@ from boxsdk import Client
from boxsdk.auth import OAuth2

legacy_auth = OAuth2(
client_id="...",
client_secret="...",
access_token="...",
refresh_token="..."
client_id="...", client_secret="...", access_token="...", refresh_token="..."
)
legacy_client = Client(legacy_auth)

Expand All @@ -230,7 +239,7 @@ legacy_auth = JWTAuth(
client_secret="...",
enterprise_id="...",
jwt_key_id="...",
rsa_private_key_file_sys_path="path/to/key.pem"
rsa_private_key_file_sys_path="path/to/key.pem",
)
legacy_client = Client(legacy_auth)

Expand All @@ -241,7 +250,9 @@ gen_client = legacy_client.get_sdk_gen_client()
if user_id:
gen_auth = legacy_client.get_authentication()
gen_auth = gen_auth.with_user_subject(user_id)
gen_client = BoxClient(auth=gen_auth, network_session=legacy_client.get_network_session())
gen_client = BoxClient(
auth=gen_auth, network_session=legacy_client.get_network_session()
)
```

### CCG Authentication
Expand All @@ -250,11 +261,7 @@ if user_id:
from boxsdk import Client
from boxsdk.auth import CCGAuth

legacy_auth = CCGAuth(
client_id="...",
client_secret="...",
enterprise_id="..."
)
legacy_auth = CCGAuth(client_id="...", client_secret="...", enterprise_id="...")
legacy_client = Client(legacy_auth)

# Get generated client
Expand All @@ -273,7 +280,7 @@ legacy_client = Client(OAuth2(...))
gen_client = legacy_client.get_sdk_gen_client(
network_options={
"additional_headers": {"X-Custom-Header": "value"},
"retry_strategy": custom_retry_strategy
"retry_strategy": custom_retry_strategy,
}
)
```
Expand All @@ -289,6 +296,7 @@ The `LegacyTokenStorageAdapter` implements the `TokenStorage` interface from `bo
- `clear()`: Clears stored tokens

The adapter converts between:

- Legacy format: `(access_token: str, refresh_token: Optional[str])`
- Generated format: `AccessToken(access_token, refresh_token, expires_in, token_type)`

Expand All @@ -304,6 +312,7 @@ Each authentication type is handled specifically:
### Network Configuration Conversion

Network settings are extracted from:

- `Session.api_config`: Base URLs, OAuth URLs
- `Session.proxy_config`: Proxy settings
- `Session._default_headers`: Custom headers
Expand Down
16 changes: 14 additions & 2 deletions test/box_sdk_gen/test/ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,12 @@ def testAIExtractStructuredWithFields():
parent=UploadFileAttributesParentField(id='0'),
),
string_to_byte_stream(
'My name is John Doe. I was born in 4th July 1990. I am 34 years old. My hobby is guitar.'
''.join(
[
'My name is John Doe. I was born in 4th July 1990. I am 34 years old. My hobby is guitar. My UUID is ',
get_uuid(),
]
)
),
)
file: FileFull = uploaded_files.entries[0]
Expand Down Expand Up @@ -300,8 +305,10 @@ def testAIExtractStructuredWithFields():
],
),
],
include_confidence_score=True,
ai_agent=ai_extract_structured_agent_basic_text_config,
)
assert not response.confidence_score == None
assert to_string(response.answer.get('hobby')) == to_string(['guitar'])
assert to_string(response.answer.get('firstName')) == 'John'
assert to_string(response.answer.get('lastName')) == 'Doe'
Expand All @@ -318,7 +325,12 @@ def testAIExtractStructuredWithMetadataTemplate():
parent=UploadFileAttributesParentField(id='0'),
),
string_to_byte_stream(
'My name is John Doe. I was born in 4th July 1990. I am 34 years old. My hobby is guitar.'
''.join(
[
'My name is John Doe. I was born in 4th July 1990. I am 34 years old. My hobby is guitar. My UUID is ',
get_uuid(),
]
)
),
)
file: FileFull = uploaded_files.entries[0]
Expand Down
Loading