Skip to content

Commit

Permalink
[Cosmos] create new async user agent for async client (Azure#22263)
Browse files Browse the repository at this point in the history
* initial commit

* Client Constructor (Azure#20310)

* Removed some stuff

* Looking at constructors

* Updated request

* Added client close

* working client creation

Co-authored-by: simorenoh <[email protected]>

* read database

database read works, but ignored exception is returned:
Fatal error on SSL transport
NoneType has no attribute 'send' (_loop._proactor.send)
RuntimeError: Event loop is closed
Unclosed connector/ connection

* Update simon_testfile.py

* with coroutine

Added methods needed to use async with when initializing client, but logs output "Exception ignored... Runtime Error: Event loop is closed"

* Update simon_testfile.py

* small changes

* async with returns no exceptions

* async read container

* async item read

* cleaning up

* create item/ database methods

* item delete working

* docs replace functionality

missing upsert and other resources

* upsert functionality

missing read_all_items and both query methods for container class

* missing query methods

* CRUD for udf, sproc, triggers

* initial query logic + container methods

* missing some execution logic and tests

* oops

* fully working queries

* small fix to query_items()

also fixed README and added examples_async

* Update _cosmos_client_connection_async.py

* Update _cosmos_client_connection.py

* documentation update

* updated MIT dates and get_user_client() description

* Update CHANGELOG.md

* Delete simon_testfile.py

* leftover retry utility

* Update README.md

* docs and removed six package

* changes based on comments

still missing discussion resolution on SSL verification and tests for async functionality under test module (apart from samples which are basically end to end tests)

* small change in type hints

* updated readme

* fixes based on conversations

* added missing type comments

* update changelog for ci pipeline

* added typehints, moved params into keywords, added decorators, made _connection_policy private

* changes based on sync with central sdk

* remove is_system_key from scripts (only used in execute_sproc)

is_system_key verifies that an empty partition key is properly dealt with if ['partitionKey']['systemKey'] exists in the container options - however, we do not allow containers to be created with empty partition key values in the python sdk, so the functionality is needless

* Revert "remove is_system_key from scripts (only used in execute_sproc)"

Reverting last commit, will find way to init is_system_key for now

* async script proxy using composition

* pylint

* capitalized constants

* Apply suggestions from code review

Clarifying comments for README

Co-authored-by: Gahl Levy <[email protected]>

* closing python code snippet

* last doc updates

* Update sdk/cosmos/azure-cosmos/CHANGELOG.md

Co-authored-by: Simon Moreno <[email protected]>

* version update

* cosmos updates for release

* create async user agent for debugging

* added basic tests

* made user agent private so users know it's not something they need to use

* bring in private user agent

Co-authored-by: annatisch <[email protected]>
Co-authored-by: Gahl Levy <[email protected]>
Co-authored-by: Travis Prescott <[email protected]>
  • Loading branch information
4 people authored and rakshith91 committed Apr 10, 2022
1 parent f84acc4 commit 9f00f84
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 3 deletions.
3 changes: 3 additions & 0 deletions sdk/cosmos/azure-cosmos/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
This version and all future versions will require Python 3.6+. Python 2.7 is no longer supported.
We will also be removing support for Python 3.6 and will only support Python 3.7+ starting December 2022.

#### Other Changes
- Added async user agent for async client

### 4.3.0b1 (2021-12-14)
**New features**
- Added language native async i/o client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,12 @@ def __init__(
proxy = host if url.port else host + ":" + str(self.connection_policy.ProxyConfiguration.Port)
proxies.update({url.scheme: proxy})

self._user_agent = _utils.get_user_agent()

policies = [
HeadersPolicy(**kwargs),
ProxyPolicy(proxies=proxies),
UserAgentPolicy(base_user_agent=_utils.get_user_agent(), **kwargs),
UserAgentPolicy(base_user_agent=self._user_agent, **kwargs),
ContentDecodePolicy(),
retry_policy,
CustomHookPolicy(**kwargs),
Expand Down
7 changes: 7 additions & 0 deletions sdk/cosmos/azure-cosmos/azure/cosmos/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ def get_user_agent():
return user_agent


def get_user_agent_async():
os_name = safe_user_agent_header(platform.platform())
python_version = safe_user_agent_header(platform.python_version())
user_agent = "azsdk-python-cosmos-async/{} Python/{} ({})".format(VERSION, python_version, os_name)
return user_agent


def safe_user_agent_header(s):
if s is None:
s = "unknown"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,14 @@ def __init__(
host = self.connection_policy.ProxyConfiguration.Host
url = urlparse(host)
proxy = host if url.port else host + ":" + str(self.connection_policy.ProxyConfiguration.Port)
proxies.update({url.scheme : proxy})
proxies.update({url.scheme: proxy})

self._user_agent = _utils.get_user_agent_async()

policies = [
HeadersPolicy(**kwargs),
ProxyPolicy(proxies=proxies),
UserAgentPolicy(base_user_agent=_utils.get_user_agent(), **kwargs),
UserAgentPolicy(base_user_agent=self._user_agent, **kwargs),
ContentDecodePolicy(),
retry_policy,
CustomHookPolicy(**kwargs),
Expand Down
53 changes: 53 additions & 0 deletions sdk/cosmos/azure-cosmos/test/test_client_user_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# The MIT License (MIT)
# Copyright (c) 2021 Microsoft Corporation

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest

import azure.cosmos.cosmos_client as sync_client
import azure.cosmos.aio.cosmos_client as async_client
import pytest
import asyncio
from test_config import _test_config

# This test class serves to test user-configurable options and verify they are
# properly set and saved into the different object instances that use these
# user-configurable settings.

pytestmark = pytest.mark.cosmosEmulator


@pytest.mark.usefixtures("teardown")
class TestClientUserAgent(unittest.TestCase):

async def test_client_user_agent(self):
client_sync = sync_client.CosmosClient(url=_test_config.host, credential=_test_config.masterKey)
client_async = async_client.CosmosClient(url=_test_config.host, credential=_test_config.masterKey)

self.assertTrue(client_sync.client_connection._user_agent.startswith("azsdk-python-cosmos/"))
self.assertTrue(client_async.client_connection._user_agent.startswith("azsdk-python-cosmos-async/"))
self.assertTrue(client_async.client_connection._user_agent != client_sync.client_connection._user_agent)

await client_async.close()


if __name__ == "__main__":
event_loop = asyncio.get_event_loop()
event_loop.run_until_complete(unittest.main())

0 comments on commit 9f00f84

Please sign in to comment.