Skip to content

Commit 39bc27b

Browse files
author
Chien Yuan Chang
committed
[SAMPLE-UPDATE] sample_grant_copy_auth
1 parent 0cb07ea commit 39bc27b

File tree

2 files changed

+173
-77
lines changed

2 files changed

+173
-77
lines changed

sdk/contentunderstanding/azure-ai-contentunderstanding/samples/async_samples/sample_grant_copy_auth_async.py

Lines changed: 86 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,45 @@
99
1010
DESCRIPTION:
1111
This sample demonstrates how to grant copy authorization and copy an analyzer from a source
12-
resource to a target resource (cross-resource copying). This is useful for copying analyzers
13-
between different Azure resources or subscriptions.
12+
Microsoft Foundry resource to a target Microsoft Foundry resource (cross-resource copying).
13+
This is useful for copying analyzers between different Azure resources or subscriptions.
1414
15-
The grant_copy_authorization and copy_analyzer APIs allow you to copy an analyzer between
16-
different Azure resources:
15+
ABOUT CROSS-RESOURCE COPYING:
16+
The `grant_copy_authorization` and `copy_analyzer` APIs allow you to copy an analyzer
17+
between different Azure resources:
1718
- Cross-resource copy: Copies an analyzer from one Azure resource to another
1819
- Authorization required: You must grant copy authorization before copying
19-
- Use cases: Cross-subscription copying, resource migration, multi-region deployment
2020
21-
Note: For same-resource copying (copying within the same Azure resource), use the
22-
sample_copy_analyzer_async.py sample instead.
21+
When to use cross-resource copying:
22+
- Copy between subscriptions: Move analyzers between different Azure subscriptions
23+
- Multi-region deployment: Deploy the same analyzer to multiple regions
24+
- Resource migration: Migrate analyzers from one resource to another
25+
- Environment promotion: Promote analyzers from development to production across resources
26+
27+
Note: For same-resource copying (copying within the same Microsoft Foundry resource),
28+
use the sample_copy_analyzer_async.py sample instead.
29+
30+
PREREQUISITES:
31+
To get started you'll need a **Microsoft Foundry resource**. For this cross-resource scenario,
32+
you'll also need:
33+
- Source Microsoft Foundry resource with model deployments configured
34+
- Target Microsoft Foundry resource with model deployments configured
35+
36+
Important: Both the source and target resources require the 'Cognitive Services User' role
37+
to be granted to the credential used to run the code. This role is required for cross-resource
38+
copying operations. Without this role, the grant_copy_authorization and copy_analyzer
39+
operations will fail with authorization errors.
40+
41+
HOW AUTHORIZATION WORKS:
42+
The grant_copy_authorization method must be called on the source Microsoft Foundry resource
43+
(where the analyzer currently exists). This is because the source resource needs to explicitly
44+
grant permission for its analyzer to be copied. The method creates a time-limited authorization
45+
record that grants permission to a specific target resource.
46+
47+
Where copy is performed: The copy_analyzer method must be called on the target Microsoft Foundry
48+
resource (where the analyzer will be copied to). This is because the target resource is the one
49+
receiving and creating the copy. When the target resource calls copy_analyzer, the service
50+
validates that authorization was previously granted by the source resource.
2351
2452
USAGE:
2553
python sample_grant_copy_auth_async.py
@@ -37,7 +65,8 @@
3765
Example resource ID format:
3866
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{name}
3967
40-
Note: Both source and target AI Foundry Resources require 'Cognitive Services User' role for cross-subscription copy.
68+
Important: Cross-resource copying requires credential-based authentication (such as DefaultAzureCredential).
69+
API keys cannot be used for cross-resource operations.
4170
"""
4271

4372
import asyncio
@@ -100,7 +129,7 @@ async def main() -> None:
100129
target_resource_id = os.environ["AZURE_CONTENT_UNDERSTANDING_TARGET_RESOURCE_ID"]
101130
target_region = os.environ["AZURE_CONTENT_UNDERSTANDING_TARGET_REGION"]
102131

103-
# Create clients
132+
# Create source and target clients using DefaultAzureCredential
104133
source_client = ContentUnderstandingClient(endpoint=source_endpoint, credential=source_credential)
105134
target_client = ContentUnderstandingClient(endpoint=target_endpoint, credential=target_credential)
106135

@@ -120,34 +149,39 @@ async def main() -> None:
120149
try:
121150
async with source_client, target_client:
122151
# Step 1: Create the source analyzer
152+
# The analyzer must exist in the source resource before it can be copied
123153
print(f"\nStep 1: Creating source analyzer '{source_analyzer_id}'...")
124154

155+
source_config = ContentAnalyzerConfig(
156+
enable_formula=False,
157+
enable_layout=True,
158+
enable_ocr=True,
159+
estimate_field_source_and_confidence=True,
160+
return_details=True,
161+
)
162+
163+
source_field_schema = ContentFieldSchema(
164+
name="company_schema",
165+
description="Schema for extracting company information",
166+
fields={
167+
"company_name": ContentFieldDefinition(
168+
type=ContentFieldType.STRING,
169+
method=GenerationMethod.EXTRACT,
170+
description="Name of the company",
171+
),
172+
"total_amount": ContentFieldDefinition(
173+
type=ContentFieldType.NUMBER,
174+
method=GenerationMethod.EXTRACT,
175+
description="Total amount on the document",
176+
),
177+
},
178+
)
179+
125180
source_analyzer = ContentAnalyzer(
126181
base_analyzer_id="prebuilt-document",
127182
description="Source analyzer for cross-resource copying",
128-
config=ContentAnalyzerConfig(
129-
enable_formula=False,
130-
enable_layout=True,
131-
enable_ocr=True,
132-
estimate_field_source_and_confidence=True,
133-
return_details=True,
134-
),
135-
field_schema=ContentFieldSchema(
136-
name="company_schema",
137-
description="Schema for extracting company information",
138-
fields={
139-
"company_name": ContentFieldDefinition(
140-
type=ContentFieldType.STRING,
141-
method=GenerationMethod.EXTRACT,
142-
description="Name of the company",
143-
),
144-
"total_amount": ContentFieldDefinition(
145-
type=ContentFieldType.NUMBER,
146-
method=GenerationMethod.EXTRACT,
147-
description="Total amount on the document",
148-
),
149-
},
150-
),
183+
config=source_config,
184+
field_schema=source_field_schema,
151185
models={"completion": "gpt-4.1"},
152186
)
153187

@@ -158,24 +192,36 @@ async def main() -> None:
158192
await poller.result()
159193
print(f" Source analyzer created successfully!")
160194

161-
# Step 2: Grant copy authorization from source
162-
# Grant authorization on the source client for copying to the target resource
195+
# Step 2: Grant copy authorization
196+
# Authorization must be granted by the source resource before the target resource can copy
197+
# The grant_copy_authorization method takes:
198+
# - The source analyzer ID to be copied
199+
# - The target Azure resource ID that is allowed to receive the copy
200+
# - The target region where the copy will be performed (optional, defaults to current region)
163201
print(f"\nStep 2: Granting copy authorization from source resource...")
202+
print(f" Target Azure Resource ID: {target_resource_id}")
203+
print(f" Target Region: {target_region}")
164204

165205
copy_auth = await source_client.grant_copy_authorization(
166206
analyzer_id=source_analyzer_id,
167207
target_azure_resource_id=target_resource_id,
168208
target_region=target_region,
169209
)
170210

171-
print(f" Authorization granted!")
211+
print(f" Authorization granted successfully!")
172212
print(f" Target Azure Resource ID: {copy_auth.target_azure_resource_id}")
173213
print(f" Target Region: {target_region}")
174214
print(f" Expires at: {copy_auth.expires_at}")
175215

176-
# Step 3: Copy analyzer using authorization
177-
# Copy is performed on the target client, copying from source to target
216+
# Step 3: Copy analyzer to target resource
217+
# The copy_analyzer method must be called on the target client because the target
218+
# resource is the one receiving and creating the copy. The target resource validates
219+
# that authorization was previously granted by the source resource.
178220
print(f"\nStep 3: Copying analyzer from source to target...")
221+
print(f" Source Analyzer ID: {source_analyzer_id}")
222+
print(f" Source Azure Resource ID: {source_resource_id}")
223+
print(f" Source Region: {source_region}")
224+
print(f" Target Analyzer ID: {target_analyzer_id}")
179225

180226
copy_poller = await target_client.begin_copy_analyzer(
181227
analyzer_id=target_analyzer_id,
@@ -184,14 +230,16 @@ async def main() -> None:
184230
source_region=source_region,
185231
)
186232
await copy_poller.result()
187-
print(f" Analyzer copied successfully!")
233+
print(f" Analyzer copied successfully to target resource!")
188234

189235
# Step 4: Verify the copy
236+
# Retrieve the analyzer from the target resource to verify the copy was successful
190237
print(f"\nStep 4: Verifying the copied analyzer...")
191238
copied_analyzer = await target_client.get_analyzer(analyzer_id=target_analyzer_id)
192239
print(f" Target Analyzer ID: {copied_analyzer.analyzer_id}")
193240
print(f" Description: {copied_analyzer.description}")
194241
print(f" Status: {copied_analyzer.status}")
242+
print(f"\nCross-resource copy completed successfully!")
195243

196244
finally:
197245
# Clean up - create new client instances for cleanup since the original ones are closed

sdk/contentunderstanding/azure-ai-contentunderstanding/samples/sample_grant_copy_auth.py

Lines changed: 87 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,45 @@
99
1010
DESCRIPTION:
1111
This sample demonstrates how to grant copy authorization and copy an analyzer from a source
12-
resource to a target resource (cross-resource copying). This is useful for copying analyzers
13-
between different Azure resources or subscriptions.
12+
Microsoft Foundry resource to a target Microsoft Foundry resource (cross-resource copying).
13+
This is useful for copying analyzers between different Azure resources or subscriptions.
1414
15-
The grant_copy_authorization and copy_analyzer APIs allow you to copy an analyzer between
16-
different Azure resources:
15+
ABOUT CROSS-RESOURCE COPYING:
16+
The `grant_copy_authorization` and `copy_analyzer` APIs allow you to copy an analyzer
17+
between different Azure resources:
1718
- Cross-resource copy: Copies an analyzer from one Azure resource to another
1819
- Authorization required: You must grant copy authorization before copying
19-
- Use cases: Cross-subscription copying, resource migration, multi-region deployment
2020
21-
Note: For same-resource copying (copying within the same Azure resource), use the
22-
sample_copy_analyzer.py sample instead.
21+
When to use cross-resource copying:
22+
- Copy between subscriptions: Move analyzers between different Azure subscriptions
23+
- Multi-region deployment: Deploy the same analyzer to multiple regions
24+
- Resource migration: Migrate analyzers from one resource to another
25+
- Environment promotion: Promote analyzers from development to production across resources
26+
27+
Note: For same-resource copying (copying within the same Microsoft Foundry resource),
28+
use the sample_copy_analyzer.py sample instead.
29+
30+
PREREQUISITES:
31+
To get started you'll need a **Microsoft Foundry resource**. For this cross-resource scenario,
32+
you'll also need:
33+
- Source Microsoft Foundry resource with model deployments configured
34+
- Target Microsoft Foundry resource with model deployments configured
35+
36+
Important: Both the source and target resources require the 'Cognitive Services User' role
37+
to be granted to the credential used to run the code. This role is required for cross-resource
38+
copying operations. Without this role, the grant_copy_authorization and copy_analyzer
39+
operations will fail with authorization errors.
40+
41+
HOW AUTHORIZATION WORKS:
42+
The grant_copy_authorization method must be called on the source Microsoft Foundry resource
43+
(where the analyzer currently exists). This is because the source resource needs to explicitly
44+
grant permission for its analyzer to be copied. The method creates a time-limited authorization
45+
record that grants permission to a specific target resource.
46+
47+
Where copy is performed: The copy_analyzer method must be called on the target Microsoft Foundry
48+
resource (where the analyzer will be copied to). This is because the target resource is the one
49+
receiving and creating the copy. When the target resource calls copy_analyzer, the service
50+
validates that authorization was previously granted by the source resource.
2351
2452
USAGE:
2553
python sample_grant_copy_auth.py
@@ -37,7 +65,8 @@
3765
Example resource ID format:
3866
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.CognitiveServices/accounts/{name}
3967
40-
Note: Both source and target AI Foundry Resources require 'Cognitive Services User' role for cross-subscription copy.
68+
Important: Cross-resource copying requires credential-based authentication (such as DefaultAzureCredential).
69+
API keys cannot be used for cross-resource operations.
4170
"""
4271

4372
import os
@@ -99,7 +128,7 @@ def main() -> None:
99128
target_resource_id = os.environ["AZURE_CONTENT_UNDERSTANDING_TARGET_RESOURCE_ID"]
100129
target_region = os.environ["AZURE_CONTENT_UNDERSTANDING_TARGET_REGION"]
101130

102-
# Create clients
131+
# Create source and target clients using DefaultAzureCredential
103132
source_client = ContentUnderstandingClient(endpoint=source_endpoint, credential=source_credential)
104133
target_client = ContentUnderstandingClient(endpoint=target_endpoint, credential=target_credential)
105134

@@ -118,34 +147,39 @@ def main() -> None:
118147

119148
try:
120149
# Step 1: Create the source analyzer
150+
# The analyzer must exist in the source resource before it can be copied
121151
print(f"\nStep 1: Creating source analyzer '{source_analyzer_id}'...")
122152

153+
source_config = ContentAnalyzerConfig(
154+
enable_formula=False,
155+
enable_layout=True,
156+
enable_ocr=True,
157+
estimate_field_source_and_confidence=True,
158+
return_details=True,
159+
)
160+
161+
source_field_schema = ContentFieldSchema(
162+
name="company_schema",
163+
description="Schema for extracting company information",
164+
fields={
165+
"company_name": ContentFieldDefinition(
166+
type=ContentFieldType.STRING,
167+
method=GenerationMethod.EXTRACT,
168+
description="Name of the company",
169+
),
170+
"total_amount": ContentFieldDefinition(
171+
type=ContentFieldType.NUMBER,
172+
method=GenerationMethod.EXTRACT,
173+
description="Total amount on the document",
174+
),
175+
},
176+
)
177+
123178
source_analyzer = ContentAnalyzer(
124179
base_analyzer_id="prebuilt-document",
125180
description="Source analyzer for cross-resource copying",
126-
config=ContentAnalyzerConfig(
127-
enable_formula=False,
128-
enable_layout=True,
129-
enable_ocr=True,
130-
estimate_field_source_and_confidence=True,
131-
return_details=True,
132-
),
133-
field_schema=ContentFieldSchema(
134-
name="company_schema",
135-
description="Schema for extracting company information",
136-
fields={
137-
"company_name": ContentFieldDefinition(
138-
type=ContentFieldType.STRING,
139-
method=GenerationMethod.EXTRACT,
140-
description="Name of the company",
141-
),
142-
"total_amount": ContentFieldDefinition(
143-
type=ContentFieldType.NUMBER,
144-
method=GenerationMethod.EXTRACT,
145-
description="Total amount on the document",
146-
),
147-
},
148-
),
181+
config=source_config,
182+
field_schema=source_field_schema,
149183
models={"completion": "gpt-4.1"},
150184
)
151185

@@ -156,24 +190,36 @@ def main() -> None:
156190
poller.result()
157191
print(f" Source analyzer created successfully!")
158192

159-
# Step 2: Grant copy authorization from source
160-
# Grant authorization on the source client for copying to the target resource
193+
# Step 2: Grant copy authorization
194+
# Authorization must be granted by the source resource before the target resource can copy
195+
# The grant_copy_authorization method takes:
196+
# - The source analyzer ID to be copied
197+
# - The target Azure resource ID that is allowed to receive the copy
198+
# - The target region where the copy will be performed (optional, defaults to current region)
161199
print(f"\nStep 2: Granting copy authorization from source resource...")
200+
print(f" Target Azure Resource ID: {target_resource_id}")
201+
print(f" Target Region: {target_region}")
162202

163203
copy_auth = source_client.grant_copy_authorization(
164204
analyzer_id=source_analyzer_id,
165205
target_azure_resource_id=target_resource_id,
166206
target_region=target_region,
167207
)
168208

169-
print(f" Authorization granted!")
209+
print(f" Authorization granted successfully!")
170210
print(f" Target Azure Resource ID: {copy_auth.target_azure_resource_id}")
171211
print(f" Target Region: {target_region}")
172212
print(f" Expires at: {copy_auth.expires_at}")
173213

174-
# Step 3: Copy analyzer using authorization
175-
# Copy is performed on the target client, copying from source to target
214+
# Step 3: Copy analyzer to target resource
215+
# The copy_analyzer method must be called on the target client because the target
216+
# resource is the one receiving and creating the copy. The target resource validates
217+
# that authorization was previously granted by the source resource.
176218
print(f"\nStep 3: Copying analyzer from source to target...")
219+
print(f" Source Analyzer ID: {source_analyzer_id}")
220+
print(f" Source Azure Resource ID: {source_resource_id}")
221+
print(f" Source Region: {source_region}")
222+
print(f" Target Analyzer ID: {target_analyzer_id}")
177223

178224
copy_poller = target_client.begin_copy_analyzer(
179225
analyzer_id=target_analyzer_id,
@@ -182,17 +228,19 @@ def main() -> None:
182228
source_region=source_region,
183229
)
184230
copy_poller.result()
185-
print(f" Analyzer copied successfully!")
231+
print(f" Analyzer copied successfully to target resource!")
186232

187233
# Step 4: Verify the copy
234+
# Retrieve the analyzer from the target resource to verify the copy was successful
188235
print(f"\nStep 4: Verifying the copied analyzer...")
189236
copied_analyzer = target_client.get_analyzer(analyzer_id=target_analyzer_id)
190237
print(f" Target Analyzer ID: {copied_analyzer.analyzer_id}")
191238
print(f" Description: {copied_analyzer.description}")
192239
print(f" Status: {copied_analyzer.status}")
240+
print(f"\nCross-resource copy completed successfully!")
193241

194242
finally:
195-
# Clean up
243+
# Clean up: Delete both source and target analyzers
196244
print(f"\nCleaning up...")
197245
try:
198246
source_client.delete_analyzer(analyzer_id=source_analyzer_id)

0 commit comments

Comments
 (0)