From 4afffb5327448414bd757ae55614e0c36b72444a Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Mon, 14 Dec 2020 17:35:58 -0500 Subject: [PATCH 1/7] fix formatting for generate docs --- docs/generate/directives.md | 1 + docs/generate/readme.md | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/generate/directives.md b/docs/generate/directives.md index 386c3f8d8c5..886ff5e742d 100644 --- a/docs/generate/directives.md +++ b/docs/generate/directives.md @@ -146,6 +146,7 @@ Here is the before and after of the generated code. We have put all of these Python-specific directives in a [config file][directive_readme] for you to refer to. + [lro_poller_docs]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.polling.lropoller?view=azure-python diff --git a/docs/generate/readme.md b/docs/generate/readme.md index 74dd73d7890..baf312f0fdb 100644 --- a/docs/generate/readme.md +++ b/docs/generate/readme.md @@ -1,7 +1,11 @@ # Generating Python Clients with AutoRest -Most of the information you'll need to generate a Python client can be found in the general docs [here](https://github.com/Azure/autorest/tree/master/docs/generate/readme.md). In these docs, we go over a couple Python-specific scenarios. +Most of the information you'll need to generate a Python client can be found in the general docs [here][general]. In these docs, we go over a couple Python-specific scenarios. -## Generating Multi API code +* [Generating Multi API code][multiapi] +* [Generating with Directives][directives] -See the docs [here](./multiapi.md) + +[general]: https://github.com/Azure/autorest/tree/master/docs/generate/readme.md +[multiapi]: ./multiapi.md +[directives]: ./directives.md \ No newline at end of file From 91d7b60b59cabce1be7421f990eb7ccbecd9036e Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Mon, 14 Dec 2020 17:36:10 -0500 Subject: [PATCH 2/7] initializing client --- docs/client/initializing.md | 83 +++++++++++++++++++++++++++++++++++++ docs/client/readme.md | 13 ++++++ 2 files changed, 96 insertions(+) create mode 100644 docs/client/initializing.md diff --git a/docs/client/initializing.md b/docs/client/initializing.md new file mode 100644 index 00000000000..d52fdc2f315 --- /dev/null +++ b/docs/client/initializing.md @@ -0,0 +1,83 @@ +# 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 +ours is called `PetsClient`. + +Putting this together, we import our client like so: + +```python +from azure.pets import PetsClient +``` + +## Initializing Your Client + +Next, on to initialization. Your constructor can take any number of parameters. If your client has no parameters (no client parameters detailed +in the swagger (TODO: link to swagger docs) and you choose to generate without credentials), initializing your client would just look like + +```python +from azure.pets import PetsClient + +client = PetsClient() +``` + +However, by default we generate clients with credentials, so continue on to [Authenticating Your Client](#authenticating-your-client "Authenticating Your Client") +to find out how to input a credential. + +## Authenticating Your Client + +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`][identity_pypi] library for AAD authentication. For this example, +we use the most common [`DefaultAzureCredential`][default_azure_credential]. + +As an installation note, the [`azure-identity`][identity_pypi] 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)) +``` + +## 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") +``` + + + +[multiapi_generation]: ../generate/multiapi.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 +[identity_pypi]: https://pypi.org/project/azure-identity/ +[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 +[flag_index]: https://github.com/Azure/autorest/tree/master/docs/generate/flags.md diff --git a/docs/client/readme.md b/docs/client/readme.md index e69de29bb2d..e1b9eac725c 100644 --- a/docs/client/readme.md +++ b/docs/client/readme.md @@ -0,0 +1,13 @@ +# Using the Python Client + +After [generating][generate] your client, this section tells you how to actually use your generated client. + +* Initializing your Python Client +* Calling operations with your Python Client +* Error Handling +* Tracing +* Dependencies your Generated Code Has + + +[generate]: https://github.com/Azure/autorest/tree/master/docs/generate/readme.md +[initializing]: ./initializing.md \ No newline at end of file From 7341cbb065f0609a66f36da2214d36d62d8d2a80 Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Tue, 15 Dec 2020 13:31:03 -0500 Subject: [PATCH 3/7] how to call operations with your client --- docs/client/operations.md | 157 ++++++++++++++++++ docs/client/readme.md | 9 +- docs/generate/directives.md | 6 +- docs/generate/examples/directives/readme.md | 2 +- .../directives.json => pollingPaging.json} | 4 +- 5 files changed, 167 insertions(+), 11 deletions(-) create mode 100644 docs/client/operations.md rename docs/generate/examples/{directives/directives.json => pollingPaging.json} (95%) diff --git a/docs/client/operations.md b/docs/client/operations.md new file mode 100644 index 00000000000..53efbac7bf6 --- /dev/null +++ b/docs/client/operations.md @@ -0,0 +1,157 @@ +# 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` +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 +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), +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, +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 +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. + + + +[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]: ../generate/examples/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 \ No newline at end of file diff --git a/docs/client/readme.md b/docs/client/readme.md index e1b9eac725c..965b4f886c2 100644 --- a/docs/client/readme.md +++ b/docs/client/readme.md @@ -2,12 +2,13 @@ After [generating][generate] your client, this section tells you how to actually use your generated client. -* Initializing your Python Client -* Calling operations with your Python Client +* Initializing Your Python Client +* Calling Operations with Your Python Client * Error Handling * Tracing -* Dependencies your Generated Code Has +* Dependencies Your Generated Code Has [generate]: https://github.com/Azure/autorest/tree/master/docs/generate/readme.md -[initializing]: ./initializing.md \ No newline at end of file +[initializing]: ./initializing.md +[operations]: ./operations.md \ No newline at end of file diff --git a/docs/generate/directives.md b/docs/generate/directives.md index 886ff5e742d..0c4af9843b7 100644 --- a/docs/generate/directives.md +++ b/docs/generate/directives.md @@ -18,7 +18,7 @@ So, if you were modifying the `put` operation under the path `/directives/pollin Where they differ is in the conditions your custom objects need to fulfill, how you mark the directive, and how they change the generated code. -The following scenarios all use the [directives.json][directives_swagger] example swagger. +The following scenarios all use the [pollingPaging.json][polling_paging_swagger] example swagger. * [Generate with a Custom Poller](#generate-with-a-custom-poller "Generate with a Custom Poller") @@ -152,7 +152,7 @@ We have put all of these Python-specific directives in a [config file][directive [lro_poller_docs]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.polling.lropoller?view=azure-python [azure_core_pypi]: https://pypi.org/project/azure-core/ [async_lro_poller_docs]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.polling.asynclropoller?view=azure-python -[directives_swagger]: ./examples/directives/directives.json +[polling_paging_swagger]: ./examples/pollingPaging.json [lro_base_polling_docs]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.polling.base_polling.lrobasepolling?view=azure-python [async_lro_base_polling_docs]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.polling.async_base_polling.asynclrobasepolling?view=azure-python @@ -163,5 +163,3 @@ We have put all of these Python-specific directives in a [config file][directive [item_paged_docs]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.paging.itempaged?view=azure-python [async_item_paged_docs]: https://docs.microsoft.com/en-us/python/api/azure-core/azure.core.async_paging.asyncitempaged?view=azure-python - -[directive_readme]: ./examples/directives/readme.md diff --git a/docs/generate/examples/directives/readme.md b/docs/generate/examples/directives/readme.md index 3e40f66a593..7feb55fab4e 100644 --- a/docs/generate/examples/directives/readme.md +++ b/docs/generate/examples/directives/readme.md @@ -3,7 +3,7 @@ ### Settings ``` yaml -input-file: directives.json +input-file: pollingPaging.json namespace: python.directives package-name: python-directives output-folder: $(python-sdks-folder)/directives/python-directives diff --git a/docs/generate/examples/directives/directives.json b/docs/generate/examples/pollingPaging.json similarity index 95% rename from docs/generate/examples/directives/directives.json rename to docs/generate/examples/pollingPaging.json index 3fc1cf129ba..6cebec831ff 100644 --- a/docs/generate/examples/directives/directives.json +++ b/docs/generate/examples/pollingPaging.json @@ -1,8 +1,8 @@ { "swagger": "2.0", "info": { - "title": "Directives Example", - "description": "Show how to use directives to get custom paging / polling generation", + "title": "Polling Paging Example", + "description": "Show polling and paging generation", "version": "1.0.0" }, "host": "localhost:3000", From bc0b9aecbb658dc6d474506aa18baf3809e1e40c Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Tue, 15 Dec 2020 13:46:09 -0500 Subject: [PATCH 4/7] include part detailing authenticaing with custom credential --- docs/client/initializing.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/client/initializing.md b/docs/client/initializing.md index d52fdc2f315..676cd79313d 100644 --- a/docs/client/initializing.md +++ b/docs/client/initializing.md @@ -56,6 +56,12 @@ 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, +you can still pass it in to the client. However, you may have to use a custom authentication policy to handle the credential. That can also be passed in to the +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 From 34366d508eab1129dd5ab728632cf319957bc762 Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Tue, 15 Dec 2020 14:23:59 -0500 Subject: [PATCH 5/7] add error handling --- docs/client/error_handling.md | 63 +++++++++++++++++++++++++++++++++++ docs/client/readme.md | 9 ++--- 2 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 docs/client/error_handling.md diff --git a/docs/client/error_handling.md b/docs/client/error_handling.md new file mode 100644 index 00000000000..964e5588dc9 --- /dev/null +++ b/docs/client/error_handling.md @@ -0,0 +1,63 @@ +# 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. + +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)) +``` + +## 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: + +```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) +``` + + + +[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 \ No newline at end of file diff --git a/docs/client/readme.md b/docs/client/readme.md index 965b4f886c2..c6cbeb5ec4a 100644 --- a/docs/client/readme.md +++ b/docs/client/readme.md @@ -2,13 +2,14 @@ After [generating][generate] your client, this section tells you how to actually use your generated client. -* Initializing Your Python Client -* Calling Operations with Your Python Client -* Error Handling +* [Initializing Your Python Client][initializing] +* [Calling Operations with Your Python Client][operations] +* [Error Handling][error_handling] * Tracing * Dependencies Your Generated Code Has [generate]: https://github.com/Azure/autorest/tree/master/docs/generate/readme.md [initializing]: ./initializing.md -[operations]: ./operations.md \ No newline at end of file +[operations]: ./operations.md +[error_handling]: ./error_handling.md \ No newline at end of file From e8f17d098c2a0b9e0690190c9c9aa774b4108be2 Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Tue, 15 Dec 2020 14:53:29 -0500 Subject: [PATCH 6/7] add tracing docs --- docs/client/readme.md | 5 ++- docs/client/tracing.md | 92 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 docs/client/tracing.md diff --git a/docs/client/readme.md b/docs/client/readme.md index c6cbeb5ec4a..9afa9ad1690 100644 --- a/docs/client/readme.md +++ b/docs/client/readme.md @@ -5,11 +5,12 @@ After [generating][generate] your client, this section tells you how to actually * [Initializing Your Python Client][initializing] * [Calling Operations with Your Python Client][operations] * [Error Handling][error_handling] -* Tracing +* [Tracing][tracing] * Dependencies Your Generated Code Has [generate]: https://github.com/Azure/autorest/tree/master/docs/generate/readme.md [initializing]: ./initializing.md [operations]: ./operations.md -[error_handling]: ./error_handling.md \ No newline at end of file +[error_handling]: ./error_handling.md +[tracing]: ./tracing.md \ No newline at end of file diff --git a/docs/client/tracing.md b/docs/client/tracing.md new file mode 100644 index 00000000000..9ddd558a8bd --- /dev/null +++ b/docs/client/tracing.md @@ -0,0 +1,92 @@ +# Tracing + +Our generated code can natively support tracing libraries [`OpenCensus`][open_census] and [`OpenTelemetry`][open_telemetry]. To do so, generate with flag `--trace` (see our [flag index][flag_index] for more information). + +## OpenCensus + +First step is to install our [`OpenCensus` library][our_open_census_library]: + +```python +pip install azure-core-tracing-opencensus +``` + +Our generated SDKs handle retrieving context for you, so there's no need to pass in any context. Additionally, the +OpenCensus threading plugin is included when installing this package. + +Since there is no explicit context you need to pass, you just create your usual OpenCensus tracer and call the generated SDKs. +The following example uses [`Azure Monitor`'s][azure_monitor] exporter, but you can use any exporter ([Zipkin][zipkin], etc.). + +```python +from opencensus.ext.azure.trace_exporter import AzureExporter +from opencensus.trace.tracer import Tracer +from opencensus.trace.samplers import AlwaysOnSampler + +from azure.identity import DefaultAzureCredential +from azure.pets import PetsClient + +exporter = AzureExporter( + instrumentation_key="uuid of the instrumentation key (see your Azure Monitor account)" +) +tracer = Tracer(exporter=exporter, sampler=AlwaysOnSampler()) +with tracer.span(name="MyApplication") as span: + client = PetsClient(credential=DefaultAzureCredential()) + dog = client.get_dog() # Call will be traced +``` + +## OpenTelemetry + +First step is to install our [`OpenTelemetry` library][our_open_telemetry_library]: + +```python +pip install azure-core-tracing-opentelemetry +``` + +Our generated SDKs handle retrieving context for you, so there's no need to pass in any context. +Since there is no explicit context you need to pass, you just create your usual OpenTelemetry tracer and call the generated SDKs. +The following example uses [`Azure Monitor`'s][azure_monitor] exporter, but you can use any exporter ([Zipkin][zipkin], etc.). + +```python +# Declare OpenTelemetry as an enabled tracing plugin for Azure SDKs +from azure.core.settings import settings +from azure.core.tracing.ext.opentelemetry_span import OpenTelemetrySpan + +settings.tracing_implementation = OpenTelemetrySpan + +# In the below example, we use the Azure Monitor exporter, but you can use anything OpenTelemetry supports +from azure_monitor import AzureMonitorSpanExporter +exporter = AzureMonitorSpanExporter( + instrumentation_key="uuid of the instrumentation key (see your Azure Monitor account)" +) + +# Regular open telemetry usage from here, see https://github.com/open-telemetry/opentelemetry-python +# for details +from opentelemetry import trace +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import ConsoleSpanExporter +from opentelemetry.sdk.trace.export import SimpleExportSpanProcessor + +# Simple console exporter +exporter = ConsoleSpanExporter() + +trace.set_tracer_provider(TracerProvider()) +tracer = trace.get_tracer(__name__) +trace.get_tracer_provider().add_span_processor( + SimpleExportSpanProcessor(exporter) +) + +# Example with our Pets example +from azure.identity import DefaultAzureCredential +from azure.pets import PetsClient + +client = PetsClient(credential=DefaultAzureCredential()) +dog = client.get_dog() # Call will be traced +``` + + +[open_census]: https://opencensus.io/ +[open_telemetry]: https://opentelemetry.io/ +[flag_index]: https://github.com/Azure/autorest/tree/master/docs/generate/flags.md +[our_open_census_library]: https://pypi.org/project/azure-core-tracing-opencensus/ +[azure_monitor]: https://pypi.org/project/opentelemetry-azure-monitor/ +[zipkin]: https://zipkin.io/ +[our_open_telemetry_library]: https://pypi.org/project/azure-core-tracing-opentelemetry/ From 3c7898280babeecb60de6a48731e9a8ed9f04557 Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Tue, 15 Dec 2020 15:36:08 -0500 Subject: [PATCH 7/7] add min dependencies --- docs/client/initializing.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/client/initializing.md b/docs/client/initializing.md index 676cd79313d..55b06792c5c 100644 --- a/docs/client/initializing.md +++ b/docs/client/initializing.md @@ -15,6 +15,19 @@ Putting this together, we import our client like so: from azure.pets import PetsClient ``` +### 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 now|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 Your Client Next, on to initialization. Your constructor can take any number of parameters. If your client has no parameters (no client parameters detailed @@ -32,10 +45,10 @@ to find out how to input a credential. ## Authenticating Your Client 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`][identity_pypi] library for AAD authentication. For this example, +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`][identity_pypi] library is not a requirement in the basic `setup.py` file we generate +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 @@ -81,9 +94,12 @@ client = PetsClient(credential=DefaultAzureCredential(), api_version="v1") [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 -[identity_pypi]: https://pypi.org/project/azure-identity/ [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 -[flag_index]: https://github.com/Azure/autorest/tree/master/docs/generate/flags.md