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

Python guideline reorg/MQ2020 #2177

Merged
merged 21 commits into from
Mar 10, 2021
Merged

Python guideline reorg/MQ2020 #2177

merged 21 commits into from
Mar 10, 2021

Conversation

johanste
Copy link
Member

No description provided.

@johanste johanste requested a review from annatisch December 17, 2020 23:27
Copy link
Member

@annatisch annatisch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some preliminary comments :)

docs/python/implementation.md Show resolved Hide resolved
docs/python/implementation.md Outdated Show resolved Hide resolved
docs/python/implementation.md Outdated Show resolved Hide resolved
docs/python/implementation.md Outdated Show resolved Hide resolved
docs/python/_includes/example_client.py Show resolved Hide resolved
docs/python/design.md Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
@johanste johanste changed the title Initial draft of guideline reorg/MQ2020 Initial draft of python guideline reorg/MQ2020 Jan 6, 2021
Copy link
Member

@tjprescott tjprescott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for giving me a good excuse to read the Python guidelines in their entirety. Some comments for consideration.

docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/implementation.md Outdated Show resolved Hide resolved
docs/python/implementation.md Outdated Show resolved Hide resolved
docs/python/implementation.md Outdated Show resolved Hide resolved
docs/python/implementation.md Show resolved Hide resolved
@annatisch
Copy link
Member

Working on some updates and feedback here:
johanste#1

@johanste johanste changed the title Initial draft of python guideline reorg/MQ2020 Python guideline reorg/MQ2020 Feb 1, 2021
@johanste johanste marked this pull request as ready for review February 1, 2021 01:02
Copy link
Member

@annelo-msft annelo-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome; left some comments. Thanks, Johan!!

docs/python/design.md Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Show resolved Hide resolved
docs/python/design.md Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/implementation.md Outdated Show resolved Hide resolved
docs/python/implementation.md Show resolved Hide resolved
docs/python/implementation.md Show resolved Hide resolved
docs/python/implementation.md Show resolved Hide resolved
johanste and others added 3 commits February 2, 2021 13:39
Co-authored-by: Anne Thompson <annelo@microsoft.com>
Co-authored-by: Anne Thompson <annelo@microsoft.com>
Co-authored-by: Anne Thompson <annelo@microsoft.com>
@xiangyan99
Copy link
Member

Could you add some guideline for the scenario

def _do_something(input):
    do_something

class Client():
    def method(self):
        _do_something()

vs

class Client():
    @classmethod
    def _do_something(cls, input):
         do_something

    def method(self):
         cls._do_something()

vs

class Client():
    @staticmethod
    def _do_something(input):
         do_something

    def method(self):
         Client._do_something()


TODO: Add an example of the basic API shape similar to what's shown in the code sample <!--[here](https://azure.github.io/azure-sdk/java_design.html#java-sync-client-shape)--> but with the equivalent in Python. Please include code illustrations of the following areas:
{% include requirement/MUST id="python-general-version-support" %} support Python 2.7 and 3.5.3+.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this now be upgraded to 3.6+?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to announce 3.5 deprecation first. Which we probably have to very soon given that other dependencies are also giving up on it.

docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
docs/python/design.md Outdated Show resolved Hide resolved
Comment on lines 515 to 518
{% include requirement/MUST id="python-codestyle-pep484" %} provide type hints [PEP484](https://www.python.org/dev/peps/pep-0484/) for publicly documented classes and functions.

- See the [suggested syntax for Python 2.7 and 2.7-3.x straddling code](https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code) for guidance for Python 2.7 compatible code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean all code should use the 2.7 syntax, or should 3.x code (like async clients) use the 3.x compatible syntax??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python 3 only code should use Python 3 syntax.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth calling out since some might just apply the 2.7 syntax everywhere

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Called out. Hopefully I'll be able to clean up all references on "how to do X for Python 2.7 support) soon. Very soon. Any day now.

Copy link
Member

@tjprescott tjprescott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added guidance on positional vs. kword-only would help.

Comment on lines +432 to +443
See TODO: insert link for general guidance on positional vs. optional parameters here.

{% include requirement/MUST id="python-tooling-flake8" %} use [flake8-docstrings](https://gitlab.com/pycqa/flake8-docstrings) to verify doc comments.
{% include requirement/MUST id="python-codestyle-optional-args" %} use keyword-only arguments for optional or less-often-used arguments for modules that only need to support Python 3.

{% include requirement/MUST id="python-tooling-black" %} use [Black](https://black.readthedocs.io/en/stable/) for formatting your code.
```python
# Yes
def foo(a, b, *, c, d=None):
# Note that I can even have required keyword-only arguments...
...
```

{% include requirement/SHOULD id="python-tooling-mypy" %} use [MyPy](https://mypy.readthedocs.io/en/latest/) to statically check the public surface area of your library.
{% include requirement/MUST id="python-codestyle-kwargs" %} use keyword-only arguments for arguments that have no obvious ordering.
Copy link
Member

@tjprescott tjprescott Feb 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great if this TODO could be resolved in this PR. Namely these two guidelines seem at odds.

Here's the scenario that came up where these guidelines caused some friction:

def __init__(self, remote_rendering_endpoint, account_id, account_domain, credential, **kwargs)

All of the positional arguments are required, but the arguments have no obvious ordering. Yet, in practice, we would recommend these all be kept positional vice kwarg-only.

It doesn't add clarity that example for the kwarg-only for optional args guidelines even says:

# Yes
def foo(a, b, *, c, d=None):
    # Note that I can even have required keyword-only arguments...
    ...

cc/ @annatisch @rikogeln

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practical terms, we can have required **kwargs as well. It's just that you have to do a runtime check. Since the intent is to - in many cases - emulate keyword-only arguments in our use of kwargs in Python 2 compatible code, I'll add this to the guidance.

On a related note, I've opened Azure/azure-sdk-for-python#16772 to track guidance on overloads since that is tangentially related to this...

:type endpoint str:
:param credential: Credentials to use when connecting to the service.
:type credential: ~azure.core.credentials.TokenCredential
:keyword apiversion: API version to use when talking to the service. Default is '2020-12-31'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small nit: apiversion in docstring doesn't match api_version naming below

|`timeout`|Timeout in seconds|All service methods|
|`headers`|Custom headers to include in the service request|All requests|Headers are added to all requests made (directly or indirectly) by the method.|
|`client_request_id`|Caller specified identification of the request.|Service operations for services that allow the client to send a client-generated correlation ID.|Examples of this include `x-ms-client-request-id` headers.|The client library **must** use this value if provided, or generate a unique value for each request when not specified.|
|`response_hook`|`callable` that is called with (response, headers) for each operation.|All service methods|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we call this raw_response_hook in azure core

Suggested change
|`response_hook`|`callable` that is called with (response, headers) for each operation.|All service methods|
|`raw_response_hook`|`callable` that is called with (response, headers) for each operation.|All service methods|


##### Specifying the Service Version

{% include requirement/MUST id="python-client-constructor-api-version-argument-1" %} accept an optional `api_version` keyword-only argument of type string. If specified, the provided api version MUST be used when interacting with the service. If the parameter is not provided, the default value MUST be the latest non-preview API version understood by the client library (if there the service has a non-preview version) or the latest preview API version understood by the client library (if the service does not have any non-preview API versions yet). This parameter MUST be available even if there is only one API version understood by the service in order to allow library developers to lock down the API version they expect to interact with the service with.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{% include requirement/MUST id="python-client-constructor-api-version-argument-1" %} accept an optional `api_version` keyword-only argument of type string. If specified, the provided api version MUST be used when interacting with the service. If the parameter is not provided, the default value MUST be the latest non-preview API version understood by the client library (if there the service has a non-preview version) or the latest preview API version understood by the client library (if the service does not have any non-preview API versions yet). This parameter MUST be available even if there is only one API version understood by the service in order to allow library developers to lock down the API version they expect to interact with the service with.
{% include requirement/MUST id="python-client-constructor-api-version-argument-1" %} accept an optional `api_version` keyword-only argument of type string. If specified, the provided api version MUST be used when interacting with the service. If the parameter is not provided, the default value MUST be the latest non-preview API version understood by the client library (if the service has a non-preview version) or the latest preview API version understood by the client library (if the service does not have any non-preview API versions yet). This parameter MUST be available even if there is only one API version understood by the service in order to allow library developers to lock down the API version they expect to interact with the service with.


{% include requirement/MAY id="python-client-constructor-api-version-argument-4" %} validate the input `api_version` value against a list of supported API versions.

{% include requirement/MAY id="python-client-constructor-api-version-argument-5" %} include all service API versions that are supported by the client library in a `ServiceVersion` enumerated value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be <Service>Version? Like TextAnalyticsVersion?

exists = client.resource_exists(name):
if not exists:
print("The resource doesn't exist...")
except azure.core.errors.ServiceRequestError:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should be azure.core.exceptions


TODO: If there are design considerations to call out that parallel the xxOptions parameters, please add those here. e.g. per the Python API Design Training Article Anna put together at **github.com/Azure/azure-sdk-pr/blob/master/training/azure-sdk-apis/getting-started/design-the-api/design-the-api-python.md#the-get-request**, what should be positional parameters vs. kwargs?
{% include requirement/MUST id="python-verioning-minor" %} increment the minor version if any new functionality is added to the package.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{% include requirement/MUST id="python-verioning-minor" %} increment the minor version if any new functionality is added to the package.
{% include requirement/MUST id="python-versioning-minor" %} increment the minor version if any new functionality is added to the package.


{% include requirement/MUST id="python-response-logical-entity" %} optimize for returning the logical entity for a given request. The logical entity MUST represent the information needed in the 99%+ case.
{% include requirement/MUST id="python-versioning-major-cross-languages" %} select a version number greater than the highest version number of any other released Track 1 package for the service in any other scope or language.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the rule we were going by was:

The maximum released version of a Track 1 library across all languages +1


{% include requirement/MUST id="python-samples-runnable" %} ensure that each sample file is runnable.

{% include requirement/MUST id="python-samples-coding-style" %} use Python 3 conventions when creating samples. Do not include Python 2 compatibility code (e.g. using [`six`](https://six.readthedocs.io)) since that will distract from what you are trying to present. Avoid using features newer than the Python 3 baseline support. The current supported Python version is 3.6.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current supported Python version is 3.6.

I thought we supported 3.5?

continuation_token: "str"

def by_page(self) -> ByPagePaged[T] ...
```

`azure.core.Paged` implements the `Paged` protocol.
`azure.core.ItemPaged` implements the `ItemPaged` protocol.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: azure.core.paging.ItemPaged

docs/python/implementation.md Show resolved Hide resolved
@johanste johanste merged commit 85eb283 into Azure:master Mar 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants