Skip to content
This repository was archived by the owner on May 22, 2026. It is now read-only.
Merged

Docs #853

Show file tree
Hide file tree
Changes from 9 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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ venv.bak/
node_modules/

# autorest default folder
generated
/generated
**/code-model-v4-no-tags.yaml

# VS code
Expand Down
76 changes: 76 additions & 0 deletions docs/client/error_handling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# <img align="center" src="../images/logo.png"> Error Handling

## General

Our generated clients raise [exceptions defined in `azure-core`][azure_core_exceptions]. While the base for all exceptions is [`AzureError`][azure_error],
[`HttpResponseError`][http_response_error] is also a common base catch-all for exceptions, as these errors are thrown in the case of a request being made, and a non-successful
status code being received from the service.
Comment thread
iscai-msft marked this conversation as resolved.

Our generated code also offers some default mapping of status codes to exceptions. These are `401` to [`ClientAuthenticationError`][client_authentication_error], `404` to
[`ResourceNotFoundError`][resource_not_found_error], and `409` to [`ResourceExistsError`][resource_exists_error].

A very basic form of error handling looks like this

```python
from azure.identity import DefaultAzureCredential
from azure.pets import PetsClient

client = PetsClient(credential=DefaultAzureCredential())
try:
dog = client.get_dog()
except HttpResponseError as e:
print("{}: {}".format(e.status_code, e.message))
```

You can also catch errors with more granularity, i.e. just catching a `ResourceExistsError`.

```python
from azure.identity import DefaultAzureCredential
from azure.pets import PetsClient

client = PetsClient(credential=DefaultAzureCredential())
try:
dog = client.get_dog()
except ResourceExistsError as e:
print(e.message)
```


## Logging

Our generated libraries use the standard [`logging`][logging] library for logging. Basic information about HTTP sessions (URLs, headers, etc.) is logged at INFO level.
Our logger's name is `azure`.

Detailed DEBUG level logging, including request/response bodies and un-redacted headers, can be enabled on a client with the logging_enable argument:
Comment thread
iscai-msft marked this conversation as resolved.

```python
import logging
import sys
from azure.identity import DefaultAzureCredential
from azure.pets import PetsClient

# Create a logger for the 'azure' SDK
logger = logging.getLogger('azure')
logger.setLevel(logging.DEBUG)

# Configure a console output
handler = logging.StreamHandler(stream=sys.stdout)
logger.addHandler(handler)

client = PetsClient(credential=DefaultAzureCredential(), logging_enable=True)
```

Network trace logging can also be enabled for any single operation:

```python
dog = client.get_dog(logging_enable=True)
```

<!-- LINKS -->
[azure_core_exceptions]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/core/azure-core#azure-core-library-exceptions
[azure_error]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.exceptions.azureerror?view=azure-python
[http_response_error]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.exceptions.httpresponseerror?view=azure-python
[client_authentication_error]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.exceptions.clientauthenticationerror?view=azure-python
[resource_not_found_error]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.exceptions.resourcenotfounderror?view=azure-python
[resource_exists_error]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.exceptions.resourceexistserror?view=azure-python
[logging]: https://docs.python.org/3.5/library/logging.html
90 changes: 90 additions & 0 deletions docs/client/initializing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# <img align="center" src="../images/logo.png"> Initializing Your Python Client

The first step to using your generated client in code is to import and initialize your client. Our SDKs are modelled such
that the client is the main point of access to the generated code.

## Importing Your Client

You import your client from the namespace specified when generating (under flag `--namespace`). For the sake of this example,
let's say the namespace is `azure.pets`. Your client's name is detailed in the swagger, (TODO link to swagger docs), and let's say
Comment thread
iscai-msft marked this conversation as resolved.
ours is called `PetsClient`.

Putting this together, we import our client like so:

```python
from azure.pets import PetsClient
```

## Minimum Dependencies of Your Client

The only scenario the generated code can force dependencies is if you generate with a `setup.py` file using the `--basic-setup-py` flag.
The following are core libraries your generated code depend on, and the minimum version we highly recommend:

| Library | Description | Min Version
|------------------|-------------|-------------
|[`azure-core`][azure_core_library]|The most important library to have installed. It provides shared exceptions and modules for all the Python SDK client libraries.|1.8.2
|[`msrest`][msrest_library]|Library mainly used for serializing and deserializing objects|0.6.18
|[`azure-mgmt-core`][azure_mgmt_core_library]|Required if you're generating mgmt plane code (see `--azure-arm` flag in our [flag index][flag_index]. Provides mgmt plane specific shared exceptions and modules.|1.2.1

> Note: We highly recommend tying your library to a major version, for instance, adding `azure-core<2.0.0` to tie the `azure-core` library to `1.x.x`

## Initializing and Authenticating Your Client

Next, on to initialization. Your constructor can take any number of parameters. By default we generate our clients with an [Azure Active Directory (AAD) token credential][aad_authentication]. We always recommend
using a [credential type][identity_credentials] obtained from the [`azure-identity`][azure_identity_library] library for AAD authentication. For this example,
we use the most common [`DefaultAzureCredential`][default_azure_credential].

As an installation note, the [`azure-identity`][azure_identity_library] library is not a requirement in the basic `setup.py` file we generate
(see `--basic-setup-py` in our [flag index][flag_index] for more information), so you would need to install this library separately.

```python
from azure.identity import DefaultAzureCredential
from azure.pets import PetsClient

client = PetsClient(credential=DefaultAzureCredential())
```

You can also have your generated client take in an [`AzureKeyCredential`][azure_key_credential] instead. To do so, generate with flag `--credential-types=AzureKeyCredential`,
and for more information on this flag, see our [flag index][flag_index]

```python
from azure.core.credentials import AzureKeyCredential
from azure.pets import PetsClient

credential = "myCredential"
client = PetsClient(credential=AzureKeyCredential(credential))
```

Currently, we only support generating credentials of type `TokenCredential` and / or `AzureKeyCredential`. If you'd like to use your own custom credential,
Comment thread
iscai-msft marked this conversation as resolved.
Outdated
you can pass the custom type into the client. However, you may have to use a custom authentication policy to handle the credential. That can also be passed in to the
Comment thread
iscai-msft marked this conversation as resolved.
client. Say your custom credential is called `MyCredential`, and the policy that handles this credential is called `MyAuthenticationPolicy`. Initializing your
client would look something like `client = PetsClient(credential=MyCredential(), authentication_policy=MyAuthenticationPolicy())`, though this of course varies
based on inputs.

## Multi API Client

Initializing your Multi API client is very similar to initializing a normal client. The only difference is there's an added optional
parameter `api_version`. With this parameter, you can specify the API version you want your client to have. If not specified, the multi
API client uses the default API version.

Using the Multi API client we generated in our [multi API generation][multiapi_generation], our example client uses default API version
`v2`. If we would like our client at runtime to have API version `v1`, we would initialize our client like:

```python
from azure.identity import DefaultAzureCredential
from azure.pets import PetsClient

client = PetsClient(credential=DefaultAzureCredential(), api_version="v1")
```

<!-- LINKS -->
[multiapi_generation]: ../generate/multiapi.md
[azure_core_library]: https://pypi.org/project/azure-core/
[msrest_library]: https://pypi.org/project/msrest/
[azure_mgmt_core_library]: https://pypi.org/project/azure-mgmt-core/
[azure_identity_library]: https://pypi.org/project/azure-identity/
[flag_index]: https://github.com/Azure/autorest/tree/master/docs/generate/flags.md
[aad_authentication]: https://docs.microsoft.com/en-us/azure/cognitive-services/authentication?tabs=powershell#authenticate-with-azure-active-directory
[identity_credentials]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/identity/azure-identity#credentials
[default_azure_credential]: https://docs.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python
[azure_key_credential]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.credentials.azurekeycredential?view=azure-python
29 changes: 29 additions & 0 deletions docs/client/models.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# <img align="center" src="../images/logo.png"> Accessing Models and Enums

## General

Models and enums are generated in the `models` namespace. So, say you are using package `azure.pets`. To access model `Dog`, you would use the following code
snippet

```
from azure.pets.models import Dog
```

Enums are also listed in the `models` namespace, so say you have enum class `DogTypes`. To access the `DALMATION` enum, your code would look like

```
from azure.pets.models import DogTypes

my_dog_type = DogTypes.DALMATION
```

## Multi API

There is also a `models` module in a multi API client. There, you can access the latest version of each models.

If you want to access a specific API version's models, you can do so through the [`models()`][models_ex] class method we expose on the multi API client.
It accepts optional parameter `api_version`. If specified, it will retrieve the models from that API version. Otherwise, retrieves models from the
default API version the code was generated with.
Comment thread
iscai-msft marked this conversation as resolved.
Outdated

<!-- LINKS -->
[models_ex]: https://github.com/Azure/autorest.python/blob/autorestv3/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_multiapi_service_client.py#L91
157 changes: 157 additions & 0 deletions docs/client/operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# <img align="center" src="../images/logo.png"> Calling Operations with Your Python Client

AutoRest provides both synchronous and asynchronous method overloads for each service operation.
Depending on your swagger definition, operations can be accessed through operation groups (TODO: link to swagger docs) on the client,
or directly on the client.

## Operation Group vs No Operation Group

If your swagger defines an operation group for your operation (for example, in this swagger, the operation `list`
Comment thread
iscai-msft marked this conversation as resolved.
Outdated
is part of operation group `application`), you would access the operation through `client.application.list()`.

If there's no operation group, as in [this][mixin_example] case, you would access the operation directly from the client
itself, i.e. `client.get_dog()`.

## Regular Operations

### Sync Operations

We will be using the [example swagger][pets_swagger] in our main docs repo. After [initializing][initializing] our client, we
Comment thread
iscai-msft marked this conversation as resolved.
call our operation like this:

```python
from azure.identity import DefaultAzureCredential
from azure.pets import PetsClient

client = PetsClient(credential=DefaultAzureCredential())
dog = client.get_dog()
```

### Async Operations

When calling our async operations, we use our async client, which is in a different module. Following the [example above](#sync-operations Sync Operations),
Comment thread
iscai-msft marked this conversation as resolved.
Outdated
our call to `get_dog` looks like this:

```python
import asyncio
from azure.identity import DefaultAzureCredential
from azure.pets.aio import PetsClient

async def get_my_dog():
async with PetsClient(credential=DefaultAzureCredential()) as client:
dog = await client.get_dog()

loop = asyncio.get_event_loop()
loop.run_until_complete(get_my_dog())
loop.close()
```

## Long Running Operations

Long-running operations are operations which consist of an initial request sent to the service to start an operation, followed by polling the service at intervals to determine whether the operation has completed or failed, and if it has succeeded, to get the result.

In concurrence with our [python guidelines][poller_guidelines], all of our long running operations are prefixed with `begin_`, to signify the starting of the long running operation.

For our example, we will use the long running operation generated from [this][example_swagger] swagger. Let's say we generated this swagger with namespace `azure.lro`.

### Sync Long Running Operations

By default, our sync long running operations return an [`LROPoller`][lro_poller] polling object, though there [are ways][custom_poller] of changing this. Calling `.wait()` on this poller
waits for the operation to finish, while calling `.result()` both waits on the operation and returns the final response.

```python
from azure.identity import DefaultAzureCredential
from azure.lro import PollingPagingExampleClient
from azure.lro.models import Product

client = PollingPagingExampleClient(credential=DefaultAzureCredential())
input_product = Product(id=1, name="My Polling Example")
poller = client.begin_basic_polling(product=input_product)
output_product = poller.result()
```

### Async Long Running Operations

By default, our async long running operations return an [`AsyncLROPoller`][asyync_lro_poller] polling object, though there [are ways][custom_poller] of changing this. Same as the sync version,
Comment thread
iscai-msft marked this conversation as resolved.
Outdated
calling `.wait()` on this poller waits for the operation to finish, while calling `.result()` both waits on the operation and returns the final response.

```python
import asyncio
from azure.identity import DefaultAzureCredential
from azure.lro.aio import PollingPagingExampleClient
from azure.lro.models import Product

async def basic_polling():
async with PollingPagingExampleClient(credential=DefaultAzureCredential()) as client:
input_product = Product(id=1, name="My Polling Example")
poller = await client.begin_basic_polling(product=input_product)
output_product = await poller.result()

loop = asyncio.get_event_loop()
loop.run_until_complete(basic_polling())
loop.close()
```

## Paging Operations

A paging operation pages through lists of data, returning an iterator for the items. Network calls get made when users start iterating through the output, not when the operation
is initially called.

For our example, we will use the long running operation generated from [this][example_swagger] swagger. Let's say we generated this swagger with namespace `azure.paging`.

### Sync Paging Operations

By default, our sync paging operations return an [`ItemPaged`][item_paged] pager, though there [are ways][custom_pager] of changing this. The initial call to the function returns
the pager, but doesn't make any network calls. Instead, calls are made when users start iterating, with each network call returning a page of data.

```python
from azure.identity import DefaultAzureCredential
from azure.paging import PollingPagingExampleClient

client = PollingPagingExampleClient(credential=DefaultAzureCredential())
pages = client.basic_paging()
[print(page) for page in pages]
```

### Async Paging Operations

By default, our sync paging operations return an [`AsyncItemPaged`][async_item_paged] pager, though there [are ways][custom_pager] of changing this. Since network calls aren't
Comment thread
iscai-msft marked this conversation as resolved.
Outdated
made until starting to page, our generated operation is synchronous, and there's no need to wait the initial call to the function. Since network calls are made when iterating,
we have to do async looping.

```python
import asyncio
from azure.identity import DefaultAzureCredential
from azure.paging.aio import PollingPagingExampleClient

async def basic_paging():
async with PollingPagingExampleClient(credential=DefaultAzureCredential()) as client:
pages = client.basic_paging() # note how there's no awaiting here
async for page in pages: # since network calls are only made during iteration, we await the network calls when iterating
print(page)

loop = asyncio.get_event_loop()
loop.run_until_complete(basic_paging())
loop.close()
```


## Advanced: LRO + paging

We also support generating a long running paging operation. In this case, we return a poller from the operation, and the final result from the poller is
a pager that pages through the final lists of data.


<!-- LINKS -->
[operation_group_example]: https://github.com/Azure/azure-rest-api-specs/blob/master/specification/batch/data-plane/Microsoft.Batch/stable/2020-09-01.12.0/BatchService.json#L64
[mixin_example]: https://github.com/Azure/autorest/blob/new_docs/docs/openapi/examples/pets.json#L20
[pets_swaggger]: https://github.com/Azure/autorest/blob/new_docs/docs/openapi/examples/pets.json
[initializing]: ./initializing.md
[lro_poller]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.polling.lropoller?view=azure-python
[custom_poller]: ../generate/directives.md#generate-with-a-custom-poller
[example_swagger]: ../samples/specification/directives/pollingPaging.json
[poller_guidelines]: https://azure.github.io/azure-sdk/python_design.html#service-operations
[async_lro_poller]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.polling.asynclropoller?view=azure-python
[item_paged]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.paging.itempaged?view=azure-python
[custom_pager]: ../generate/directives.md#generate-with-a-custom-pager
[async_item_paged]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.async_paging.asyncitempaged?view=azure-python
17 changes: 17 additions & 0 deletions docs/client/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# <img align="center" src="../images/logo.png"> Using the Python Client

After [generating][generate] your client, this section tells you how to actually use your generated client.

* [Initializing Your Python Client][initializing]
* [Calling Operations with Your Python Client][operations]
* [Accessing Models and Enums][models]
* [Error Handling][error_handling]
* [Tracing][tracing]

<!-- LINKS -->
[generate]: https://github.com/Azure/autorest/tree/master/docs/generate/readme.md
[initializing]: ./initializing.md
[operations]: ./operations.md
[models]: ./models.md
[error_handling]: ./error_handling.md
[tracing]: ./tracing.md
Loading