diff --git a/sdk/cosmos/azure-cosmos/CHANGELOG.md b/sdk/cosmos/azure-cosmos/CHANGELOG.md index 425dc184ce63..514c98c30ed9 100644 --- a/sdk/cosmos/azure-cosmos/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos/CHANGELOG.md @@ -8,6 +8,7 @@ Method call will now require an 'id' field to be present in the document body. #### Other Changes +- Deprecated offer-named methods in favor of their new throughput-named counterparts (`read_offer` -> `get_throughput`). - Marked the GetAuthorizationHeader method for deprecation since it will no longer be public in a future release. - Added samples showing how to configure retry options for both the sync and async clients. - Deprecated the `connection_retry_policy` and `retry_options` options in the sync client. @@ -37,7 +38,7 @@ Method call will now require an 'id' field to be present in the document body. - Added new **provisional** `max_integrated_cache_staleness_in_ms` parameter to read item and query items APIs in order to make use of the **preview** CosmosDB integrated cache functionality. Please see [Azure Cosmos DB integrated cache](https://docs.microsoft.com/azure/cosmos-db/integrated-cache) for more details. -- Added support for split-proof queries for the async client +- Added support for split-proof queries for the async client. ### Bugs fixed - Default consistency level for the sync and async clients is no longer `Session` and will instead be set to the diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_container.py b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_container.py index b326b8577f80..8cedae5e0136 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_container.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_container.py @@ -32,7 +32,7 @@ from .._base import build_options as _build_options, validate_cache_staleness_value from ..exceptions import CosmosResourceNotFoundError from ..http_constants import StatusCodes -from ..offer import Offer +from ..offer import ThroughputProperties from ._scripts import ScriptsProxy from ..partition_key import NonePartitionKeyValue @@ -58,11 +58,11 @@ class ContainerProxy(object): """ def __init__( - self, - client_connection: CosmosClientConnection, - database_link: str, - id: str, # pylint: disable=redefined-builtin - properties: Dict[str, Any] = None + self, + client_connection: CosmosClientConnection, + database_link: str, + id: str, # pylint: disable=redefined-builtin + properties: Dict[str, Any] = None ) -> None: self.client_connection = client_connection self.id = id @@ -113,8 +113,8 @@ def _set_partition_key(self, partition_key) -> Union[str, Awaitable]: @distributed_trace_async async def read( - self, - **kwargs: Any + self, + **kwargs: Any ) -> Dict[str, Any]: """Read the container properties. @@ -151,9 +151,9 @@ async def read( @distributed_trace_async async def create_item( - self, - body: Dict[str, Any], - **kwargs: Any + self, + body: Dict[str, Any], + **kwargs: Any ) -> Dict[str, Any]: """Create an item in the container. @@ -208,10 +208,10 @@ async def create_item( @distributed_trace_async async def read_item( - self, - item: Union[str, Dict[str, Any]], - partition_key: Union[str, int, float, bool], - **kwargs: Any + self, + item: Union[str, Dict[str, Any]], + partition_key: Union[str, int, float, bool], + **kwargs: Any ) -> Dict[str, Any]: """Get the item identified by `item`. @@ -257,8 +257,8 @@ async def read_item( @distributed_trace def read_all_items( - self, - **kwargs: Any + self, + **kwargs: Any ) -> AsyncItemPaged[Dict[str, Any]]: """List all the items in the container. @@ -296,9 +296,9 @@ def read_all_items( @distributed_trace def query_items( - self, - query: Union[str, Dict[str, Any]], - **kwargs: Any + self, + query: Union[str, Dict[str, Any]], + **kwargs: Any ) -> AsyncItemPaged[Dict[str, Any]]: """Return all results matching the given `query`. @@ -387,8 +387,8 @@ def query_items( @distributed_trace def query_items_change_feed( - self, - **kwargs: Any + self, + **kwargs: Any ) -> AsyncItemPaged[Dict[str, Any]]: """Get a sorted list of items that were changed, in the order in which they were modified. @@ -434,9 +434,9 @@ def query_items_change_feed( @distributed_trace_async async def upsert_item( - self, - body: Dict[str, Any], - **kwargs: Any + self, + body: Dict[str, Any], + **kwargs: Any ) -> Dict[str, Any]: """Insert or update the specified item. @@ -481,10 +481,10 @@ async def upsert_item( @distributed_trace_async async def replace_item( - self, - item: Union[str, Dict[str, Any]], - body: Dict[str, Any], - **kwargs: Any + self, + item: Union[str, Dict[str, Any]], + body: Dict[str, Any], + **kwargs: Any ) -> Dict[str, Any]: """Replaces the specified item if it exists in the container. @@ -528,10 +528,10 @@ async def replace_item( @distributed_trace_async async def delete_item( - self, - item: Union[str, Dict[str, Any]], - partition_key: Union[str, int, float, bool], - **kwargs: Any + self, + item: Union[str, Dict[str, Any]], + partition_key: Union[str, int, float, bool], + **kwargs: Any ) -> None: """Delete the specified item from the container. @@ -571,17 +571,17 @@ async def delete_item( response_hook(self.client_connection.last_response_headers, result) @distributed_trace_async - async def read_offer(self, **kwargs: Any) -> Offer: - """Read the Offer object for this container. + async def get_throughput(self, **kwargs: Any) -> ThroughputProperties: + """Get the ThroughputProperties object for this container. - If no Offer already exists for the container, an exception is raised. + If no ThroughputProperties already exists for the container, an exception is raised. :keyword response_hook: A callable invoked with the response metadata. :paramtype response_hook: Callable[[Dict[str, str], List[Dict[str, Any]]], None] - :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No offer exists for the container or - the offer could not be retrieved. - :returns: Offer for the container. - :rtype: ~azure.cosmos.Offer + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No throughput properties exist for the container + or the throughput properties could not be retrieved. + :returns: ThroughputProperties for the container. + :rtype: ~azure.cosmos.ThroughputProperties """ response_hook = kwargs.pop('response_hook', None) properties = await self._get_properties() @@ -590,30 +590,32 @@ async def read_offer(self, **kwargs: Any) -> Offer: "query": "SELECT * FROM root r WHERE r.resource=@link", "parameters": [{"name": "@link", "value": link}], } - offers = [offer async for offer in self.client_connection.QueryOffers(query_spec, **kwargs)] - if len(offers) == 0: + throughput_properties = [throughput async for throughput in + self.client_connection.QueryOffers(query_spec, **kwargs)] + if len(throughput_properties) == 0: raise CosmosResourceNotFoundError( status_code=StatusCodes.NOT_FOUND, - message="Could not find Offer for database " + self.database_link) + message="Could not find ThroughputProperties for container " + self.container_link) if response_hook: - response_hook(self.client_connection.last_response_headers, offers) + response_hook(self.client_connection.last_response_headers, throughput_properties) - return Offer(offer_throughput=offers[0]["content"]["offerThroughput"], properties=offers[0]) + return ThroughputProperties(offer_throughput=throughput_properties[0]["content"]["offerThroughput"], + properties=throughput_properties[0]) @distributed_trace_async - async def replace_throughput(self, throughput: int, **kwargs: Any) -> Offer: + async def replace_throughput(self, throughput: int, **kwargs: Any) -> ThroughputProperties: """Replace the container's throughput. - If no Offer already exists for the container, an exception is raised. + If no ThroughputProperties already exist for the container, an exception is raised. :param int throughput: The throughput to be set (an integer). :keyword response_hook: A callable invoked with the response metadata. :paramtype response_hook: Callable[[Dict[str, str], Dict[str, Any]], None] - :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No offer exists for the container - or the offer could not be updated. - :returns: Offer for the container, updated with new throughput. - :rtype: ~azure.cosmos.Offer + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No throughput properties exist for the container + or the throughput properties could not be updated. + :returns: ThroughputProperties for the container, updated with new throughput. + :rtype: ~azure.cosmos.ThroughputProperties """ response_hook = kwargs.pop('response_hook', None) properties = await self._get_properties() @@ -622,19 +624,21 @@ async def replace_throughput(self, throughput: int, **kwargs: Any) -> Offer: "query": "SELECT * FROM root r WHERE r.resource=@link", "parameters": [{"name": "@link", "value": link}], } - offers = [offer async for offer in self.client_connection.QueryOffers(query_spec, **kwargs)] - if len(offers) == 0: + throughput_properties = [throughput async for throughput in + self.client_connection.QueryOffers(query_spec, **kwargs)] + if len(throughput_properties) == 0: raise CosmosResourceNotFoundError( status_code=StatusCodes.NOT_FOUND, - message="Could not find Offer for database " + self.database_link) + message="Could not find Offer for container " + self.container_link) - new_offer = offers[0].copy() + new_offer = throughput_properties[0].copy() new_offer["content"]["offerThroughput"] = throughput - data = await self.client_connection.ReplaceOffer(offer_link=offers[0]["_self"], offer=offers[0], **kwargs) + data = await self.client_connection.ReplaceOffer(offer_link=throughput_properties[0]["_self"], + offer=throughput_properties[0], **kwargs) if response_hook: response_hook(self.client_connection.last_response_headers, data) - return Offer(offer_throughput=data["content"]["offerThroughput"], properties=data) + return ThroughputProperties(offer_throughput=data["content"]["offerThroughput"], properties=data) @distributed_trace def list_conflicts(self, **kwargs: Any) -> AsyncItemPaged[Dict[str, Any]]: @@ -702,7 +706,7 @@ def query_conflicts( return result @distributed_trace_async - async def read_conflict( + async def get_conflict( self, conflict: Union[str, Dict[str, Any]], partition_key: Union[str, int, float, bool], diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_database.py b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_database.py index 76af33687d05..ecba075b1657 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_database.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_database.py @@ -32,7 +32,7 @@ from ._cosmos_client_connection_async import CosmosClientConnection from .._base import build_options as _build_options from ._container import ContainerProxy -from ..offer import Offer +from ..offer import ThroughputProperties from ..http_constants import StatusCodes from ..exceptions import CosmosResourceNotFoundError from ._user import UserProxy @@ -149,10 +149,10 @@ async def read(self, **kwargs: Any) -> Dict[str, Any]: @distributed_trace_async async def create_container( - self, - id: str, # pylint: disable=redefined-builtin - partition_key: PartitionKey, - **kwargs: Any + self, + id: str, # pylint: disable=redefined-builtin + partition_key: PartitionKey, + **kwargs: Any ) -> ContainerProxy: """Create a new container with the given ID (name). @@ -241,10 +241,10 @@ async def create_container( @distributed_trace_async async def create_container_if_not_exists( - self, - id: str, # pylint: disable=redefined-builtin - partition_key: PartitionKey, - **kwargs: Any + self, + id: str, # pylint: disable=redefined-builtin + partition_key: PartitionKey, + **kwargs: Any ) -> ContainerProxy: """Create a container if it does not exist already. @@ -333,8 +333,8 @@ def get_container_client(self, container: Union[str, ContainerProxy, Dict[str, A @distributed_trace def list_containers( - self, - **kwargs + self, + **kwargs ) -> AsyncItemPaged[Dict[str, Any]]: """List the containers in the database. @@ -371,8 +371,8 @@ def list_containers( @distributed_trace def query_containers( - self, - **kwargs: Any + self, + **kwargs: Any ) -> AsyncItemPaged[Dict[str, Any]]: """List the properties for containers in the current database. @@ -408,11 +408,10 @@ def query_containers( @distributed_trace_async async def replace_container( - self, - container: Union[str, ContainerProxy, Dict[str, Any]], # Just have ContainerProxy - # move to container.replace() instead - partition_key: PartitionKey, # Remove this to make it so replace is only using proxy - **kwargs: Any + self, + container: Union[str, ContainerProxy, Dict[str, Any]], + partition_key: PartitionKey, + **kwargs: Any ) -> ContainerProxy: """Reset the properties of the container. @@ -484,9 +483,9 @@ async def replace_container( @distributed_trace_async async def delete_container( - self, - container: Union[str, ContainerProxy, Dict[str, Any]], - **kwargs: Any + self, + container: Union[str, ContainerProxy, Dict[str, Any]], + **kwargs: Any ) -> None: """Delete a container. @@ -595,9 +594,9 @@ def list_users(self, **kwargs: Any) -> AsyncItemPaged[Dict[str, Any]]: @distributed_trace def query_users( - self, - query: Union[str, Dict[str, Any]], - **kwargs: Any + self, + query: Union[str, Dict[str, Any]], + **kwargs: Any ) -> AsyncItemPaged[Dict[str, Any]]: """Return all users matching the given `query`. @@ -716,15 +715,17 @@ async def delete_user(self, user: Union[str, UserProxy, Dict[str, Any]], **kwarg response_hook(self.client_connection.last_response_headers, result) @distributed_trace_async - async def read_offer(self, **kwargs: Any) -> Offer: - """Read the Offer object for this database. + async def get_throughput(self, **kwargs: Any) -> ThroughputProperties: + """Get the ThroughputProperties object for this database. + + If no ThroughputProperties already exists for the database, an exception is raised. :keyword response_hook: A callable invoked with the response metadata. :paramtype response_hook: Callable[[Dict[str, str], List[Dict[str, Any]]], None] - :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: - If no offer exists for the database or if the offer could not be retrieved. - :returns: Offer for the database. - :rtype: ~azure.cosmos.Offer + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No throughput properties exist for the database + or the throughput properties could not be retrieved. + :returns: ThroughputProperties for the database. + :rtype: ~azure.cosmos.ThroughputProperties """ response_hook = kwargs.pop('response_hook', None) properties = await self._get_properties() @@ -733,28 +734,33 @@ async def read_offer(self, **kwargs: Any) -> Offer: "query": "SELECT * FROM root r WHERE r.resource=@link", "parameters": [{"name": "@link", "value": link}], } - offers = [offer async for offer in self.client_connection.QueryOffers(query_spec, **kwargs)] - if len(offers) == 0: + throughput_properties = [throughput async for throughput in + self.client_connection.QueryOffers(query_spec, **kwargs)] + if len(throughput_properties) == 0: raise CosmosResourceNotFoundError( status_code=StatusCodes.NOT_FOUND, - message="Could not find Offer for database " + self.database_link) + message="Could not find ThroughputProperties for database " + self.database_link) if response_hook: - response_hook(self.client_connection.last_response_headers, offers) + response_hook(self.client_connection.last_response_headers, throughput_properties) + + return ThroughputProperties(offer_throughput=throughput_properties[0]["content"]["offerThroughput"], + properties=throughput_properties[0]) - return Offer(offer_throughput=offers[0]["content"]["offerThroughput"], properties=offers[0]) @distributed_trace_async - async def replace_throughput(self, throughput: int, **kwargs: Any) -> Offer: + async def replace_throughput(self, throughput: int, **kwargs: Any) -> ThroughputProperties: """Replace the database-level throughput. - :param int throughput: The throughput to be set. + If no ThroughputProperties already exist for the database, an exception is raised. + + :param int throughput: The throughput to be set (an integer). :keyword response_hook: A callable invoked with the response metadata. :paramtype response_hook: Callable[[Dict[str, str], Dict[str, Any]], None] - :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: - If no offer exists for the database or if the offer could not be updated. - :returns: Offer for the database, updated with new throughput. - :rtype: ~azure.cosmos.Offer + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No throughput properties exist for the database + or the throughput properties could not be updated. + :returns: ThroughputProperties for the database, updated with new throughput. + :rtype: ~azure.cosmos.ThroughputProperties """ response_hook = kwargs.pop('response_hook', None) properties = await self._get_properties() @@ -763,15 +769,17 @@ async def replace_throughput(self, throughput: int, **kwargs: Any) -> Offer: "query": "SELECT * FROM root r WHERE r.resource=@link", "parameters": [{"name": "@link", "value": link}], } - offers = [offer async for offer in self.client_connection.QueryOffers(query_spec, **kwargs)] - if len(offers) == 0: + throughput_properties = [throughput async for throughput in + self.client_connection.QueryOffers(query_spec, **kwargs)] + if len(throughput_properties) == 0: raise CosmosResourceNotFoundError( status_code=StatusCodes.NOT_FOUND, message="Could not find Offer for database " + self.database_link) - new_offer = offers[0].copy() + new_offer = throughput_properties[0].copy() new_offer["content"]["offerThroughput"] = throughput - data = await self.client_connection.ReplaceOffer(offer_link=offers[0]["_self"], offer=offers[0], **kwargs) + data = await self.client_connection.ReplaceOffer(offer_link=throughput_properties[0]["_self"], + offer=throughput_properties[0], **kwargs) if response_hook: response_hook(self.client_connection.last_response_headers, data) - return Offer(offer_throughput=data["content"]["offerThroughput"], properties=data) + return ThroughputProperties(offer_throughput=data["content"]["offerThroughput"], properties=data) diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/container.py b/sdk/cosmos/azure-cosmos/azure/cosmos/container.py index 986bf930ad83..8f9b0661dd4c 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/container.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/container.py @@ -22,8 +22,8 @@ """Create, read, update and delete items in the Azure Cosmos DB SQL API service. """ -from typing import Any, Dict, List, Optional, Union, Iterable, cast, overload # pylint: disable=unused-import +from typing import Any, Dict, List, Optional, Union, Iterable, cast, overload # pylint: disable=unused-import import warnings from azure.core.tracing.decorator import distributed_trace # type: ignore @@ -32,7 +32,7 @@ from ._base import build_options, validate_cache_staleness_value from .exceptions import CosmosResourceNotFoundError from .http_constants import StatusCodes -from .offer import Offer +from .offer import ThroughputProperties from .scripts import ScriptsProxy from .partition_key import NonePartitionKeyValue @@ -626,15 +626,31 @@ def delete_item( @distributed_trace def read_offer(self, **kwargs): # type: (Any) -> Offer - """Read the Offer object for this container. + """Get the ThroughputProperties object for this container. + If no ThroughputProperties already exist for the container, an exception is raised. + :keyword Callable response_hook: A callable invoked with the response metadata. + :returns: Throughput for the container. + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No throughput properties exists for the container or + the throughput properties could not be retrieved. + :rtype: ~azure.cosmos.ThroughputProperties + """ + warnings.warn( + "read_offer is a deprecated method name, use get_throughput instead", + DeprecationWarning + ) + return self.get_throughput(**kwargs) - If no Offer already exists for the container, an exception is raised. + @distributed_trace + def get_throughput(self, **kwargs): + # type: (Any) -> ThroughputProperties + """Get the ThroughputProperties object for this container. + If no ThroughputProperties already exist for the container, an exception is raised. :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: Offer for the container. - :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No offer exists for the container or - the offer could not be retrieved. - :rtype: ~azure.cosmos.Offer + :returns: Throughput for the container. + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No throughput properties exists for the container or + the throughput properties could not be retrieved. + :rtype: ~azure.cosmos.ThroughputProperties """ response_hook = kwargs.pop('response_hook', None) properties = self._get_properties() @@ -643,30 +659,31 @@ def read_offer(self, **kwargs): "query": "SELECT * FROM root r WHERE r.resource=@link", "parameters": [{"name": "@link", "value": link}], } - offers = list(self.client_connection.QueryOffers(query_spec, **kwargs)) - if not offers: + throughput_properties = list(self.client_connection.QueryOffers(query_spec, **kwargs)) + if not throughput_properties: raise CosmosResourceNotFoundError( status_code=StatusCodes.NOT_FOUND, - message="Could not find Offer for container " + self.container_link) + message="Could not find ThroughputProperties for container " + self.container_link) if response_hook: - response_hook(self.client_connection.last_response_headers, offers) + response_hook(self.client_connection.last_response_headers, throughput_properties) - return Offer(offer_throughput=offers[0]["content"]["offerThroughput"], properties=offers[0]) + return ThroughputProperties(offer_throughput=throughput_properties[0]["content"]["offerThroughput"], + properties=throughput_properties[0]) @distributed_trace def replace_throughput(self, throughput, **kwargs): - # type: (int, Any) -> Offer + # type: (int, Any) -> ThroughputProperties """Replace the container's throughput. - If no Offer already exists for the container, an exception is raised. + If no ThroughputProperties already exist for the container, an exception is raised. :param throughput: The throughput to be set (an integer). :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: Offer for the container, updated with new throughput. - :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No offer exists for the container - or the offer could not be updated. - :rtype: ~azure.cosmos.Offer + :returns: ThroughputProperties for the container, updated with new throughput. + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No throughput properties exist for the container + or the throughput properties could not be updated. + :rtype: ~azure.cosmos.ThroughputProperties """ response_hook = kwargs.pop('response_hook', None) properties = self._get_properties() @@ -675,19 +692,20 @@ def replace_throughput(self, throughput, **kwargs): "query": "SELECT * FROM root r WHERE r.resource=@link", "parameters": [{"name": "@link", "value": link}], } - offers = list(self.client_connection.QueryOffers(query_spec, **kwargs)) - if not offers: + throughput_properties = list(self.client_connection.QueryOffers(query_spec, **kwargs)) + if not throughput_properties: raise CosmosResourceNotFoundError( status_code=StatusCodes.NOT_FOUND, message="Could not find Offer for container " + self.container_link) - new_offer = offers[0].copy() - new_offer["content"]["offerThroughput"] = throughput - data = self.client_connection.ReplaceOffer(offer_link=offers[0]["_self"], offer=offers[0], **kwargs) + new_throughput_properties = throughput_properties[0].copy() + new_throughput_properties["content"]["offerThroughput"] = throughput + data = self.client_connection.ReplaceOffer( + offer_link=throughput_properties[0]["_self"], offer=throughput_properties[0], **kwargs) if response_hook: response_hook(self.client_connection.last_response_headers, data) - return Offer(offer_throughput=data["content"]["offerThroughput"], properties=data) + return ThroughputProperties(offer_throughput=data["content"]["offerThroughput"], properties=data) @distributed_trace def list_conflicts(self, max_item_count=None, **kwargs): diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/database.py b/sdk/cosmos/azure-cosmos/azure/cosmos/database.py index bd04625c7a16..217fcc65955e 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/database.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/database.py @@ -30,7 +30,7 @@ from ._cosmos_client_connection import CosmosClientConnection from ._base import build_options from .container import ContainerProxy -from .offer import Offer +from .offer import ThroughputProperties from .http_constants import StatusCodes from .exceptions import CosmosResourceNotFoundError from .user import UserProxy @@ -727,14 +727,31 @@ def delete_user(self, user, **kwargs): @distributed_trace def read_offer(self, **kwargs): - # type: (Any) -> Offer - """Read the Offer object for this database. + # type: (Any) -> ThroughputProperties + """Get the ThroughputProperties object for this database. + If no ThroughputProperties already exist for the database, an exception is raised. + :keyword Callable response_hook: A callable invoked with the response metadata. + :returns: ThroughputProperties for the database. + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No throughput properties exists for the container or + the throughput properties could not be retrieved. + :rtype: ~azure.cosmos.ThroughputProperties + """ + warnings.warn( + "read_offer is a deprecated method name, use read_throughput instead", + DeprecationWarning + ) + return self.get_throughput(**kwargs) + @distributed_trace + def get_throughput(self, **kwargs): + # type: (Any) -> ThroughputProperties + """Get the ThroughputProperties object for this database. + If no ThroughputProperties already exist for the database, an exception is raised. :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: Offer for the database. - :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: - If no offer exists for the database or if the offer could not be retrieved. - :rtype: ~azure.cosmos.Offer + :returns: ThroughputProperties for the database. + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: No throughput properties exists for the container or + the throughput properties could not be retrieved. + :rtype: ~azure.cosmos.ThroughputProperties """ response_hook = kwargs.pop('response_hook', None) properties = self._get_properties() @@ -743,28 +760,32 @@ def read_offer(self, **kwargs): "query": "SELECT * FROM root r WHERE r.resource=@link", "parameters": [{"name": "@link", "value": link}], } - offers = list(self.client_connection.QueryOffers(query_spec, **kwargs)) - if not offers: + throughput_properties = list(self.client_connection.QueryOffers(query_spec, **kwargs)) + if not throughput_properties: raise CosmosResourceNotFoundError( status_code=StatusCodes.NOT_FOUND, - message="Could not find Offer for database " + self.database_link) + message="Could not find ThroughputProperties for database " + self.database_link) if response_hook: - response_hook(self.client_connection.last_response_headers, offers) + response_hook(self.client_connection.last_response_headers, throughput_properties) - return Offer(offer_throughput=offers[0]["content"]["offerThroughput"], properties=offers[0]) + return ThroughputProperties(offer_throughput=throughput_properties[0]["content"]["offerThroughput"], + properties=throughput_properties[0]) @distributed_trace def replace_throughput(self, throughput, **kwargs): - # type: (Optional[int], Any) -> Offer + # type: (Optional[int], Any) -> ThroughputProperties """Replace the database-level throughput. :param throughput: The throughput to be set (an integer). :keyword Callable response_hook: A callable invoked with the response metadata. :returns: Offer for the database, updated with new throughput. + :returns: ThroughputProperties for the database, updated with new throughput. :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If no offer exists for the database or if the offer could not be updated. :rtype: ~azure.cosmos.Offer + If no throughput properties exists for the database or if the throughput properties could not be updated. + :rtype: ~azure.cosmos.ThroughputProperties """ response_hook = kwargs.pop('response_hook', None) properties = self._get_properties() @@ -773,14 +794,15 @@ def replace_throughput(self, throughput, **kwargs): "query": "SELECT * FROM root r WHERE r.resource=@link", "parameters": [{"name": "@link", "value": link}], } - offers = list(self.client_connection.QueryOffers(query_spec)) - if not offers: + throughput_properties = list(self.client_connection.QueryOffers(query_spec)) + if not throughput_properties: raise CosmosResourceNotFoundError( status_code=StatusCodes.NOT_FOUND, - message="Could not find Offer for collection " + self.database_link) - new_offer = offers[0].copy() + message="Could not find ThroughputProperties for database " + self.database_link) + new_offer = throughput_properties[0].copy() new_offer["content"]["offerThroughput"] = throughput - data = self.client_connection.ReplaceOffer(offer_link=offers[0]["_self"], offer=offers[0], **kwargs) + data = self.client_connection.ReplaceOffer(offer_link=throughput_properties[0]["_self"], + offer=throughput_properties[0], **kwargs) if response_hook: response_hook(self.client_connection.last_response_headers, data) - return Offer(offer_throughput=data["content"]["offerThroughput"], properties=data) + return ThroughputProperties(offer_throughput=data["content"]["offerThroughput"], properties=data) diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/offer.py b/sdk/cosmos/azure-cosmos/azure/cosmos/offer.py index 4b99bf668055..047c61948603 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/offer.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/offer.py @@ -1,5 +1,5 @@ # The MIT License (MIT) -# Copyright (c) 2014 Microsoft Corporation +# 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 @@ -7,10 +7,8 @@ # 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 @@ -19,18 +17,20 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -"""Create offers in the Azure Cosmos DB SQL API service. +"""Create throughput properties in the Azure Cosmos DB SQL API service. """ from typing import Dict, Any -class Offer(object): - """Represents a offer in an Azure Cosmos DB SQL API container. - - To read and update offers use the associated methods on the :class:`Container`. +class ThroughputProperties(object): + """Represents the throughput properties in an Azure Cosmos DB SQL API container. + To read and update throughput properties use the associated methods on the :class:`Container`. """ def __init__(self, offer_throughput, properties=None): # pylint: disable=super-init-not-called # type: (int, Dict[str, Any]) -> None self.offer_throughput = offer_throughput self.properties = properties + + +Offer = ThroughputProperties diff --git a/sdk/cosmos/azure-cosmos/samples/container_management.py b/sdk/cosmos/azure-cosmos/samples/container_management.py index c826f9b4aa12..b3c55434eb48 100644 --- a/sdk/cosmos/azure-cosmos/samples/container_management.py +++ b/sdk/cosmos/azure-cosmos/samples/container_management.py @@ -196,7 +196,7 @@ def manage_provisioned_throughput(db, id): container = db.get_container_client(container=id) # now use its _self to query for Offers - offer = container.read_offer() + offer = container.get_throughput() print('Found Offer \'{0}\' for Container \'{1}\' and its throughput is \'{2}\''.format(offer.properties['id'], container.id, offer.properties['content']['offerThroughput'])) diff --git a/sdk/cosmos/azure-cosmos/samples/container_management_async.py b/sdk/cosmos/azure-cosmos/samples/container_management_async.py index 4b3ab86a843d..959bb2ae805b 100644 --- a/sdk/cosmos/azure-cosmos/samples/container_management_async.py +++ b/sdk/cosmos/azure-cosmos/samples/container_management_async.py @@ -215,7 +215,7 @@ async def manage_provisioned_throughput(db, id): container = db.get_container_client(id) # now use its _self to query for throughput offers - offer = await container.read_offer() + offer = await container.get_throughput() print('Found Offer \'{0}\' for Container \'{1}\' and its throughput is \'{2}\''.format(offer.properties['id'], container.id, offer.properties['content']['offerThroughput'])) diff --git a/sdk/cosmos/azure-cosmos/test/test_backwards_compatibility.py b/sdk/cosmos/azure-cosmos/test/test_backwards_compatibility.py index 23550d2e47da..a11a154a1789 100644 --- a/sdk/cosmos/azure-cosmos/test/test_backwards_compatibility.py +++ b/sdk/cosmos/azure-cosmos/test/test_backwards_compatibility.py @@ -21,11 +21,10 @@ import unittest import pytest -from azure.cosmos import cosmos_client, PartitionKey, http_constants +from azure.cosmos import cosmos_client, PartitionKey, Offer, http_constants import test_config from unittest.mock import MagicMock - # This class tests the backwards compatibility of features being deprecated to ensure users are not broken before # properly removing the methods marked for deprecation. @@ -54,6 +53,16 @@ def setUpClass(cls): cls.containerForTest = cls.databaseForTest.create_container_if_not_exists( cls.configs.TEST_COLLECTION_SINGLE_PARTITION_ID, PartitionKey(path="/id"), offer_throughput=400) + def test_offer_methods(self): + database_offer = self.databaseForTest.get_throughput() + container_offer = self.containerForTest.get_throughput() + + self.assertTrue("ThroughputProperties" in str(type(database_offer))) + self.assertTrue("ThroughputProperties" in str(type(container_offer))) + + self.assertTrue(isinstance(database_offer, Offer)) + self.assertTrue(isinstance(container_offer, Offer)) + def side_effect_populate_partition_key_range_statistics(self, *args, **kwargs): # Extract request headers from args self.assertTrue(args[2][http_constants.HttpHeaders.PopulatePartitionKeyRangeStatistics] is True) diff --git a/sdk/cosmos/azure-cosmos/test/test_crud.py b/sdk/cosmos/azure-cosmos/test/test_crud.py index 6c789f9fa694..b4cc9e8f66ed 100644 --- a/sdk/cosmos/azure-cosmos/test/test_crud.py +++ b/sdk/cosmos/azure-cosmos/test/test_crud.py @@ -279,7 +279,7 @@ def test_partitioned_collection(self): self.assertEqual(collection_definition.get('partitionKey').get('kind'), created_collection_properties['partitionKey']['kind']) - expected_offer = created_collection.read_offer() + expected_offer = created_collection.get_throughput() self.assertIsNotNone(expected_offer) @@ -2258,14 +2258,14 @@ def test_offer_read_and_query(self): partition_key=PartitionKey(path='/id', kind='Hash') ) # Read the offer. - expected_offer = collection.read_offer() + expected_offer = collection.get_throughput() collection_properties = collection.read() self.__ValidateOfferResponseBody(expected_offer, collection_properties.get('_self'), None) # Now delete the collection. db.delete_container(container=collection) # Reading fails. - self.__AssertHTTPFailureWithStatus(StatusCodes.NOT_FOUND, collection.read_offer) + self.__AssertHTTPFailureWithStatus(StatusCodes.NOT_FOUND, collection.get_throughput) def test_offer_replace(self): # Create database. @@ -2273,7 +2273,7 @@ def test_offer_replace(self): # Create collection. collection = self.configs.create_multi_partition_collection_if_not_exist(self.client) # Read Offer - expected_offer = collection.read_offer() + expected_offer = collection.get_throughput() collection_properties = collection.read() self.__ValidateOfferResponseBody(expected_offer, collection_properties.get('_self'), None) # Replace the offer. diff --git a/sdk/cosmos/azure-cosmos/test/test_partition_split_query.py b/sdk/cosmos/azure-cosmos/test/test_partition_split_query.py index b2b5c514b0a1..19e8c63ec4ab 100644 --- a/sdk/cosmos/azure-cosmos/test/test_partition_split_query.py +++ b/sdk/cosmos/azure-cosmos/test/test_partition_split_query.py @@ -64,11 +64,11 @@ def test_partition_split_query(self): self.run_queries(self.container, 100) # initial check for queries before partition split print("initial check succeeded, now reading offer until replacing is done") - offer = self.database.read_offer() + offer = self.database.get_throughput() while True: if offer.properties['content'].get('isOfferReplacePending', False): time.sleep(10) - offer = self.database.read_offer() + offer = self.database.get_throughput() else: print("offer replaced successfully, took around {} seconds".format(time.time() - offer_time)) self.run_queries(self.container, 100) # check queries work post partition split