Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finished API design tutorial #14416

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
8 changes: 8 additions & 0 deletions sdk/api-learn/azure-computation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

# Release History

-------------------

## 0.0.1 (Unreleased)

- Training day!
4 changes: 4 additions & 0 deletions sdk/api-learn/azure-computation/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
recursive-include tests *.py
include *.md
include azure/__init__.py
recursive-include samples *.py *.md
89 changes: 89 additions & 0 deletions sdk/api-learn/azure-computation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Azure Computation client library for Python SDK Training

This is a demonstration API for the API design training tutorial.
We will use this example "Computation" service to practice recognizing common API patterns and applying the design guidelines.

## Tutorial Task

The objective of this tutorial is to design a "public API" or "customization layer" for this example service.
An SDK namespace, `azure-computation`, has already been set up, with directory structure and packaging scripts in place.
The swagger specification (found at `swagger/computation.json`), and the auto-generated layer has already been pre-generated, and can be found in the `_generated` directory.

1. Follow the steps in the [API Design tutorial Setup](https://github.com/Azure/azure-sdk-pr/blob/master/training/azure-sdk-apis/tutorials/api-design-intro/setup/setup-python.md) for setting up the environment for this project.
2. Follow the steps in the [API Design tutorial](https://github.com/Azure/azure-sdk-pr/blob/master/training/azure-sdk-apis/tutorials/api-design-intro/api-design-intro/api-design-intro-python.md) for considering hero scenarios, and using them to build a public API.
3. Remember the common-patterns that we covered in the API Design presentation and see whether and how they can be applied to the API. If you wish to use one of these patterns - take a look through the [Python Design Guidelines](https://azure.github.io/azure-sdk/python_design.html#) for specifics.
- [Service Client](https://azure.github.io/azure-sdk/python_design.html#clients)
- [Authentication and `azure-identity`](https://azure.github.io/azure-sdk/python_design.html#authentication)
- [HTTP Abractions](https://azure.github.io/azure-sdk/python_design.html#service-operations)
- [Paged Collections](https://azure.github.io/azure-sdk/python_implementation.html#paged)

Examples:
- [Azure Search](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/search/azure-search-documents)
- [`list_index_names`](https://github.com/Azure/azure-sdk-for-python/blob/19db374e7ea80f1d034f547e02750b7e3b3264a7/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_search_index_client.py#L98)
- [async `list_index_names`](https://github.com/Azure/azure-sdk-for-python/blob/19db374e7ea80f1d034f547e02750b7e3b3264a7/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/aio/_search_index_client.py#L99)
- [Form Recognizer](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer)
- [`list_custom_models`](https://github.com/Azure/azure-sdk-for-python/blob/19db374e7ea80f1d034f547e02750b7e3b3264a7/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py#L208)
- [async `list_custom_models`](https://github.com/Azure/azure-sdk-for-python/blob/19db374e7ea80f1d034f547e02750b7e3b3264a7/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py#L224)

- [Long Running Operations](https://azure.github.io/azure-sdk/python_implementation.html#lropoller)

Examples:
- [Form Recognizer](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/formrecognizer/azure-ai-formrecognizer)
- [`begin_recognize_receipts`](https://github.com/Azure/azure-sdk-for-python/blob/f451b9ec96a8317b8a292bbc664653c04cc62b2c/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py#L91)
- [async `begin_recognize_receipts`](https://github.com/Azure/azure-sdk-for-python/blob/f451b9ec96a8317b8a292bbc664653c04cc62b2c/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py#L96)
- [KeyVault Secrets](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/keyvault/azure-keyvault-secrets)
- [`begin_delete_secret`](https://github.com/Azure/azure-sdk-for-python/blob/f451b9ec96a8317b8a292bbc664653c04cc62b2c/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_client.py#L296)
- [async `begin_delete_secret`](https://github.com/Azure/azure-sdk-for-python/blob/f451b9ec96a8317b8a292bbc664653c04cc62b2c/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/_client.py#L266)

4. If you wish to make adjustments to the swagger specification, follow the instructions in the [API Design tutorial Review](https://github.com/Azure/azure-sdk-pr/blob/master/training/azure-sdk-apis/tutorials/api-design-intro/review-the-api/review-the-api-python.md#regenerate-the-code) for regenerating the code.
5. Follow the instructions in the [API Design tutorial Review](https://github.com/Azure/azure-sdk-pr/blob/master/training/azure-sdk-apis/tutorials/api-design-intro/review-the-api/review-the-api-python.md#building-a-python-wheel) for generating a wheel and uploading it to APIView.

## API Review

We will follow-up this tutorial activity with a "mock arch board review" of the APIs. For this session, have an example hero scenario ready (they need not be functioning code) and your API layout in APIView.

## Structure of the example Computation service API

### Operations in the Computation service

This service has 5 APIs.

- GET `/ComputeNodes`

Get a list of available compute nodes.
- GET `/ComputeNodes/{nodeName}`

Get the properties of a single compute node.
- PUT `/ComputeNodes/{nodeName}`

Create a new compute node.
- POST `/ComputeNodes/{nodeName}/computePi`

Start a compute pi operation on a compute node.
- GET `/operation/{operationId}`

Get the compute operation status.

### Model types
- `ComputeNode`

Base compute node object.
- `LinuxComputeNote`

A Linux flavour of the compute node object.

- `WindowsComputeNode`

A Windows flavour of the compute node object.

- `PageOfComputeNodes`

A collection type that holds a list of compute nodes.

- `Operation`

Properties, including the status on a service-side operation.
- `Error`

A complex error structure that contains information for a failed request.

7 changes: 7 additions & 0 deletions sdk/api-learn/azure-computation/azure/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------

__path__ = __import__("pkgutil").extend_path(__path__, __name__)
10 changes: 10 additions & 0 deletions sdk/api-learn/azure-computation/azure/computation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------

from ._version import VERSION


__version__ = VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from ._exampleservice import ExampleService
__all__ = ['ExampleService']

try:
from ._patch import patch_sdk # type: ignore
patch_sdk()
except ImportError:
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from typing import TYPE_CHECKING

from azure.core.configuration import Configuration
from azure.core.pipeline import policies

if TYPE_CHECKING:
# pylint: disable=unused-import,ungrouped-imports
from typing import Any, Optional

from azure.core.credentials import TokenCredential

VERSION = "unknown"

class ExampleServiceConfiguration(Configuration):
"""Configuration for ExampleService.

Note that all parameters used to create this instance are saved as instance
attributes.

:param credential: Credential needed for the client to connect to Azure.
:type credential: ~azure.core.credentials.TokenCredential
:param node_name:
:type node_name: str
:param x_ms_client_request_id: Optional client-provided request id.
:type x_ms_client_request_id: str
"""

def __init__(
self,
credential, # type: "TokenCredential"
node_name, # type: str
x_ms_client_request_id=None, # type: Optional[str]
**kwargs # type: Any
):
# type: (...) -> None
if credential is None:
raise ValueError("Parameter 'credential' must not be None.")
if node_name is None:
raise ValueError("Parameter 'node_name' must not be None.")
super(ExampleServiceConfiguration, self).__init__(**kwargs)

self.credential = credential
self.node_name = node_name
self.x_ms_client_request_id = x_ms_client_request_id
self.credential_scopes = kwargs.pop('credential_scopes', [])
kwargs.setdefault('sdk_moniker', 'exampleservice/{}'.format(VERSION))
self._configure(**kwargs)

def _configure(
self,
**kwargs # type: Any
):
# type: (...) -> None
self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs)
self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs)
self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs)
self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs)
self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs)
self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs)
self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs)
self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs)
self.authentication_policy = kwargs.get('authentication_policy')
if not self.credential_scopes and not self.authentication_policy:
raise ValueError("You must provide either credential_scopes or authentication_policy as kwargs")
if self.credential and not self.authentication_policy:
self.authentication_policy = policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs)
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from typing import TYPE_CHECKING

from azure.core import PipelineClient
from msrest import Deserializer, Serializer

if TYPE_CHECKING:
# pylint: disable=unused-import,ungrouped-imports
from typing import Any, Optional

from azure.core.credentials import TokenCredential

from ._configuration import ExampleServiceConfiguration
from .operations import ComputeNodeAdministrationOperations
from .operations import ComputationOperations
from .operations import ExampleServiceOperationsMixin
from . import models


class ExampleService(ExampleServiceOperationsMixin):
"""ExampleService.

:ivar compute_node_administration: ComputeNodeAdministrationOperations operations
:vartype compute_node_administration: azure.computation.operations.ComputeNodeAdministrationOperations
:ivar computation: ComputationOperations operations
:vartype computation: azure.computation.operations.ComputationOperations
:param credential: Credential needed for the client to connect to Azure.
:type credential: ~azure.core.credentials.TokenCredential
:param node_name:
:type node_name: str
:param x_ms_client_request_id: Optional client-provided request id.
:type x_ms_client_request_id: str
:param str base_url: Service URL
"""

def __init__(
self,
credential, # type: "TokenCredential"
node_name, # type: str
x_ms_client_request_id=None, # type: Optional[str]
**kwargs # type: Any
):
# type: (...) -> None
base_url = 'None'
self._config = ExampleServiceConfiguration(credential, node_name, x_ms_client_request_id, **kwargs)
self._client = PipelineClient(base_url=base_url, config=self._config, **kwargs)

client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)}
self._serialize = Serializer(client_models)
self._deserialize = Deserializer(client_models)

self.compute_node_administration = ComputeNodeAdministrationOperations(
self._client, self._config, self._serialize, self._deserialize)
self.computation = ComputationOperations(
self._client, self._config, self._serialize, self._deserialize)

def close(self):
# type: () -> None
self._client.close()

def __enter__(self):
# type: () -> ExampleService
self._client.__enter__()
return self

def __exit__(self, *exc_details):
# type: (Any) -> None
self._client.__exit__(*exc_details)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from ._exampleservice_async import ExampleService
__all__ = ['ExampleService']
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from typing import Any, Optional, TYPE_CHECKING

from azure.core.configuration import Configuration
from azure.core.pipeline import policies

if TYPE_CHECKING:
# pylint: disable=unused-import,ungrouped-imports
from azure.core.credentials_async import AsyncTokenCredential

VERSION = "unknown"

class ExampleServiceConfiguration(Configuration):
"""Configuration for ExampleService.

Note that all parameters used to create this instance are saved as instance
attributes.

:param credential: Credential needed for the client to connect to Azure.
:type credential: ~azure.core.credentials_async.AsyncTokenCredential
:param node_name:
:type node_name: str
:param x_ms_client_request_id: Optional client-provided request id.
:type x_ms_client_request_id: str
"""

def __init__(
self,
credential: "AsyncTokenCredential",
node_name: str,
x_ms_client_request_id: Optional[str] = None,
**kwargs: Any
) -> None:
if credential is None:
raise ValueError("Parameter 'credential' must not be None.")
if node_name is None:
raise ValueError("Parameter 'node_name' must not be None.")
super(ExampleServiceConfiguration, self).__init__(**kwargs)

self.credential = credential
self.node_name = node_name
self.x_ms_client_request_id = x_ms_client_request_id
self.credential_scopes = kwargs.pop('credential_scopes', [])
kwargs.setdefault('sdk_moniker', 'exampleservice/{}'.format(VERSION))
self._configure(**kwargs)

def _configure(
self,
**kwargs: Any
) -> None:
self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs)
self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs)
self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs)
self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs)
self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs)
self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs)
self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs)
self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs)
self.authentication_policy = kwargs.get('authentication_policy')
if not self.credential_scopes and not self.authentication_policy:
raise ValueError("You must provide either credential_scopes or authentication_policy as kwargs")
if self.credential and not self.authentication_policy:
self.authentication_policy = policies.AsyncBearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs)
Loading