diff --git a/sdk/cosmos/azure-cosmos/CHANGELOG.md b/sdk/cosmos/azure-cosmos/CHANGELOG.md index e8abbd59d18c..f2335d6bed3b 100644 --- a/sdk/cosmos/azure-cosmos/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos/CHANGELOG.md @@ -3,11 +3,12 @@ ### 4.3.0b5 (Unreleased) #### Breaking Changes +- Method signatures have been updated to use keyword arguments instead of positional arguments for most method options in the async client. - Bugfix: Automatic Id generation for items was turned on for `upsert_items()` method when no 'id' value was present in document body. Method call will now require an 'id' field to be present in the document body. #### Other Changes -- Marked the GetAuthorizationMethod for deprecation since it will no longer be public in a future release. +- 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. diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/__init__.py b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/__init__.py index 606b8665cfa2..469ec0f97f03 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/__init__.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/__init__.py @@ -19,11 +19,11 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from .container import ContainerProxy +from ._container import ContainerProxy from .cosmos_client import CosmosClient -from .database import DatabaseProxy -from .user import UserProxy -from .scripts import ScriptsProxy +from ._database import DatabaseProxy +from ._user import UserProxy +from ._scripts import ScriptsProxy __all__ = ( "CosmosClient", diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/container.py b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_container.py similarity index 67% rename from sdk/cosmos/azure-cosmos/azure/cosmos/aio/container.py rename to sdk/cosmos/azure-cosmos/azure/cosmos/aio/_container.py index 58c67b07d7c6..b326b8577f80 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/container.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_container.py @@ -22,10 +22,10 @@ """Create, read, update and delete items in the Azure Cosmos DB SQL API service. """ -from typing import Any, Dict, List, Optional, Union, cast, Awaitable +from typing import Any, Dict, Optional, Union, cast, Awaitable from azure.core.async_paging import AsyncItemPaged -from azure.core.tracing.decorator import distributed_trace # pylint: disable=unused-import +from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async # type: ignore from ._cosmos_client_connection_async import CosmosClientConnection @@ -33,7 +33,7 @@ from ..exceptions import CosmosResourceNotFoundError from ..http_constants import StatusCodes from ..offer import Offer -from .scripts import ScriptsProxy +from ._scripts import ScriptsProxy from ..partition_key import NonePartitionKeyValue __all__ = ("ContainerProxy",) @@ -47,7 +47,7 @@ class ContainerProxy(object): This class should not be instantiated directly. Instead, use the :func:`~azure.cosmos.aio.database.DatabaseProxy.get_container_client` method to get an existing - container, or the :func:`~azure.cosmos.aio.database.DatabaseProxy` method to create a + container, or the :func:`~azure.cosmos.aio.database.DatabaseProxy.create_container` method to create a new container. A container in an Azure Cosmos DB SQL API database is a collection of @@ -57,29 +57,31 @@ class ContainerProxy(object): :ivar str session_token: The session token for the container. """ - def __init__(self, client_connection, database_link, id, properties=None): # pylint: disable=redefined-builtin - # type: (CosmosClientConnection, str, str, Dict[str, Any]) -> None + def __init__( + 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 self._properties = properties self.database_link = database_link self.container_link = u"{}/colls/{}".format(database_link, self.id) self._is_system_key = None - self._scripts = None # type: Optional[ScriptsProxy] + self._scripts: Optional[ScriptsProxy] = None - def __repr__(self): - # type () -> str + def __repr__(self) -> str: return "".format(self.container_link)[:1024] - async def _get_properties(self): - # type: () -> Dict[str, Any] + async def _get_properties(self) -> Dict[str, Any]: if self._properties is None: self._properties = await self.read() return self._properties @property - async def is_system_key(self): - # type: () -> bool + async def is_system_key(self) -> bool: if self._is_system_key is None: properties = await self._get_properties() self._is_system_key = ( @@ -88,20 +90,17 @@ async def is_system_key(self): return cast('bool', self._is_system_key) @property - def scripts(self): - # type: () -> ScriptsProxy + def scripts(self) -> ScriptsProxy: if self._scripts is None: self._scripts = ScriptsProxy(self, self.client_connection, self.container_link) return cast('ScriptsProxy', self._scripts) - def _get_document_link(self, item_or_link): - # type: (Union[Dict[str, Any], str]) -> str + def _get_document_link(self, item_or_link: Union[Dict[str, Any], str]) -> str: if isinstance(item_or_link, str): return u"{}/docs/{}".format(self.container_link, item_or_link) return item_or_link["_self"] - def _get_conflict_link(self, conflict_or_link): - # type: (Union[Dict[str, Any], str]) -> str + def _get_conflict_link(self, conflict_or_link: Union[Dict[str, Any], str]) -> str: if isinstance(conflict_or_link, str): return u"{}/conflicts/{}".format(self.container_link, conflict_or_link) return conflict_or_link["_self"] @@ -115,27 +114,28 @@ def _set_partition_key(self, partition_key) -> Union[str, Awaitable]: @distributed_trace_async async def read( self, - populate_partition_key_range_statistics=None, # type: Optional[bool] - populate_quota_info=None, # type: Optional[bool] - **kwargs # type: Any + **kwargs: Any ) -> Dict[str, Any]: """Read the container properties. - :param populate_partition_key_range_statistics: Enable returning partition key + :keyword bool populate_partition_key_range_statistics: Enable returning partition key range statistics in response headers. - :param populate_quota_info: Enable returning collection storage quota information in response headers. + :keyword bool populate_quota_info: Enable returning collection storage quota information in response headers. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. + :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: Raised if the container couldn't be retrieved. This includes if the container does not exist. :returns: Dict representing the retrieved container. - :rtype: dict[str, Any] + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + populate_partition_key_range_statistics = kwargs.pop('populate_partition_key_range_statistics', None) if populate_partition_key_range_statistics is not None: request_options["populatePartitionKeyRangeStatistics"] = populate_partition_key_range_statistics + populate_quota_info = kwargs.pop('populate_quota_info', None) if populate_quota_info is not None: request_options["populateQuotaInfo"] = populate_quota_info @@ -152,28 +152,38 @@ async def read( @distributed_trace_async async def create_item( self, - body, # type: Dict[str, Any] - **kwargs # type: Any + body: Dict[str, Any], + **kwargs: Any ) -> Dict[str, Any]: """Create an item in the container. To update or replace an existing item, use the :func:`ContainerProxy.upsert_item` method. - :param body: A dict-like object representing the item to create. + :param Dict[str, str] body: A dict-like object representing the item to create. :keyword pre_trigger_include: trigger id to be used as pre operation trigger. + :paramtype pre_trigger_include: str :keyword post_trigger_include: trigger id to be used as post operation trigger. - :keyword indexing_directive: Indicate whether the document should be omitted from indexing. - :keyword bool enable_automatic_id_generation: Enable automatic id generation if no id present. - :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. + :paramtype post_trigger_include: str + :keyword indexing_directive: Enumerates the possible values to indicate whether the document should + be omitted from indexing. Possible values include: 0 for Default, 1 for Exclude, or 2 for Include. + :paramtype indexing_directive: int or ~azure.cosmos.documents.IndexingDirective + :keyword enable_automatic_id_generation: Enable automatic id generation if no id present. + :paramtype enable_automatic_id_generation: bool + :keyword session_token: Token for use with Session consistency. + :paramtype session_token: str + :keyword initial_headers: Initial headers to be sent as part of the request. + :paramtype initial_headers: dict[str,str] :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A dict representing the new item. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :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: Item with the given ID already exists. - :rtype: dict[str, Any] + :returns: A dict representing the new item. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) @@ -199,25 +209,27 @@ async def create_item( @distributed_trace_async async def read_item( self, - item, # type: Union[str, Dict[str, Any]] - partition_key, # type: Any - **kwargs # type: Any + item: Union[str, Dict[str, Any]], + partition_key: Union[str, int, float, bool], + **kwargs: Any ) -> Dict[str, Any]: """Get the item identified by `item`. :param item: The ID (name) or dict representing item to retrieve. + :type item: Union[str, Dict[str, Any]] :param partition_key: Partition key for the item to retrieve. + :type partition_key: Union[str, int, float, bool] :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], Dict[str, Any]], None] **Provisional** keyword argument max_integrated_cache_staleness_in_ms - :keyword int max_integrated_cache_staleness_in_ms: - The max cache staleness for the integrated cache in milliseconds. - For accounts configured to use the integrated cache, using Session or Eventual consistency, + :keyword int max_integrated_cache_staleness_in_ms: The max cache staleness for the integrated cache in + milliseconds. For accounts configured to use the integrated cache, using Session or Eventual consistency, responses are guaranteed to be no staler than this value. - :returns: Dict representing the item to be retrieved. :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The given item couldn't be retrieved. - :rtype: dict[str, Any] + :returns: Dict representing the item to be retrieved. + :rtype: Dict[str, Any] .. admonition:: Example: @@ -246,25 +258,25 @@ async def read_item( @distributed_trace def read_all_items( self, - max_item_count=None, # type: Optional[int] - **kwargs # type: Any + **kwargs: Any ) -> AsyncItemPaged[Dict[str, Any]]: """List all the items in the container. - :param max_item_count: Max number of items to be returned in the enumeration operation. + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]]], None] **Provisional** keyword argument max_integrated_cache_staleness_in_ms - :keyword int max_integrated_cache_staleness_in_ms: - The max cache staleness for the integrated cache in milliseconds. - For accounts configured to use the integrated cache, using Session or Eventual consistency, + :keyword int max_integrated_cache_staleness_in_ms: The max cache staleness for the integrated cache in + milliseconds. For accounts configured to use the integrated cache, using Session or Eventual consistency, responses are guaranteed to be no staler than this value. :returns: An AsyncItemPaged of items (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count max_integrated_cache_staleness_in_ms = kwargs.pop('max_integrated_cache_staleness_in_ms', None) @@ -285,13 +297,8 @@ def read_all_items( @distributed_trace def query_items( self, - query, # type: str - parameters=None, # type: Optional[List[Dict[str, Any]]] - partition_key=None, # type: Optional[Any] - max_item_count=None, # type: Optional[int] - enable_scan_in_query=None, # type: Optional[bool] - populate_query_metrics=None, # type: Optional[bool] - **kwargs # type: Any + query: Union[str, Dict[str, Any]], + **kwargs: Any ) -> AsyncItemPaged[Dict[str, Any]]: """Return all results matching the given `query`. @@ -300,23 +307,25 @@ def query_items( name is "products," and is aliased as "p" for easier referencing in the WHERE clause. - :param query: The Azure Cosmos DB SQL query to execute. - :param parameters: Optional array of parameters to the query. + :param Union[str, Dict[str, Any]] query: The Azure Cosmos DB SQL query to execute. + :keyword parameters: Optional array of parameters to the query. Each parameter is a dict() with 'name' and 'value' keys. Ignored if no query is provided. - :param partition_key: Specifies the partition key value for the item. If none is provided, - a cross-partition query will be executed - :param max_item_count: Max number of items to be returned in the enumeration operation. - :param enable_scan_in_query: Allow scan on the queries which couldn't be served as + :paramtype parameters: List[Dict[str, Any]] + :keyword partition_key: Specifies the partition key value for the item. If none is provided, + a cross-partition query will be executed. + :paramtype partition_key: Union[str, int, float, bool] + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. + :keyword bool enable_scan_in_query: Allow scan on the queries which couldn't be served as indexing was opted out on the requested paths. - :param populate_query_metrics: Enable returning query metrics in response headers. + :keyword bool populate_query_metrics: Enable returning query metrics in response headers. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]]], None] **Provisional** keyword argument max_integrated_cache_staleness_in_ms - :keyword int max_integrated_cache_staleness_in_ms: - The max cache staleness for the integrated cache in milliseconds. - For accounts configured to use the integrated cache, using Session or Eventual consistency, + :keyword int max_integrated_cache_staleness_in_ms: The max cache staleness for the integrated cache in + milliseconds. For accounts configured to use the integrated cache, using Session or Eventual consistency, responses are guaranteed to be no staler than this value. :returns: An AsyncItemPaged of items (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] @@ -341,12 +350,16 @@ def query_items( """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count + populate_query_metrics = kwargs.pop('populate_query_metrics', None) if populate_query_metrics is not None: feed_options["populateQueryMetrics"] = populate_query_metrics + enable_scan_in_query = kwargs.pop('enable_scan_in_query', None) if enable_scan_in_query is not None: feed_options["enableScanInQuery"] = enable_scan_in_query + partition_key = kwargs.pop('partition_key', None) if partition_key is not None: feed_options["partitionKey"] = self._set_partition_key(partition_key) else: @@ -359,6 +372,7 @@ def query_items( if hasattr(response_hook, "clear"): response_hook.clear() + parameters = kwargs.pop('parameters', None) items = self.client_connection.QueryItems( database_or_container_link=self.container_link, query=query if parameters is None else dict(query=query, parameters=parameters), @@ -374,36 +388,37 @@ def query_items( @distributed_trace def query_items_change_feed( self, - partition_key_range_id=None, # type: Optional[str] - is_start_from_beginning=False, # type: bool - continuation=None, # type: Optional[str] - max_item_count=None, # type: Optional[int] - **kwargs # type: Any + **kwargs: Any ) -> AsyncItemPaged[Dict[str, Any]]: """Get a sorted list of items that were changed, in the order in which they were modified. - :param partition_key_range_id: ChangeFeed requests can be executed against specific partition key ranges. - This is used to process the change feed in parallel across multiple consumers. - :param partition_key: partition key at which ChangeFeed requests are targetted. - :param is_start_from_beginning: Get whether change feed should start from + :keyword bool is_start_from_beginning: Get whether change feed should start from beginning (true) or from current (false). By default it's start from current (false). - :param continuation: e_tag value to be used as continuation for reading change feed. - :param max_item_count: Max number of items to be returned in the enumeration operation. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword str partition_key_range_id: ChangeFeed requests can be executed against specific partition key + ranges. This is used to process the change feed in parallel across multiple consumers. + :keyword str continuation: e_tag value to be used as continuation for reading change feed. + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. + :keyword partition_key: partition key at which ChangeFeed requests are targeted. + :paramtype partition_key: Union[str, int, float, bool] + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]]], None] :returns: An AsyncItemPaged of items (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + partition_key = kwargs.pop("partition_key", None) + partition_key_range_id = kwargs.pop("partition_key_range_id", None) + is_start_from_beginning = kwargs.pop("is_start_from_beginning", False) + feed_options["isStartFromBeginning"] = is_start_from_beginning if partition_key_range_id is not None: feed_options["partitionKeyRangeId"] = partition_key_range_id - partition_key = kwargs.pop("partitionKey", None) if partition_key is not None: feed_options["partitionKey"] = self._set_partition_key(partition_key) - if is_start_from_beginning is not None: - feed_options["isStartFromBeginning"] = is_start_from_beginning + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count + continuation = kwargs.pop('continuation', None) if continuation is not None: feed_options["continuation"] = continuation @@ -420,34 +435,37 @@ def query_items_change_feed( @distributed_trace_async async def upsert_item( self, - body, # type: Dict[str, Any] - pre_trigger_include=None, # type: Optional[str] - post_trigger_include=None, # type: Optional[str] - **kwargs # type: Any + body: Dict[str, Any], + **kwargs: Any ) -> Dict[str, Any]: """Insert or update the specified item. If the item already exists in the container, it is replaced. If the item does not already exist, it is inserted. - :param body: A dict-like object representing the item to update or insert. - :param pre_trigger_include: trigger id to be used as pre operation trigger. - :param post_trigger_include: trigger id to be used as post operation trigger. + :param Dict[str, Any] body: A dict-like object representing the item to update or insert. + :keyword str pre_trigger_include: trigger id to be used as pre operation trigger. + :keyword str post_trigger_include: trigger id to be used as post operation trigger. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. + :paramtype session_token: str + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A dict representing the upserted item. + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :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: The given item could not be upserted. - :rtype: dict[str, Any] + :returns: A dict representing the upserted item. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) request_options["disableAutomaticIdGeneration"] = True + pre_trigger_include = kwargs.pop('pre_trigger_include', None) if pre_trigger_include is not None: request_options["preTriggerInclude"] = pre_trigger_include + post_trigger_include = kwargs.pop('post_trigger_include', None) if post_trigger_include is not None: request_options["postTriggerInclude"] = post_trigger_include @@ -464,37 +482,40 @@ async def upsert_item( @distributed_trace_async async def replace_item( self, - item, # type: Union[str, Dict[str, Any]] - body, # type: Dict[str, Any] - pre_trigger_include=None, # type: Optional[str] - post_trigger_include=None, # type: Optional[str] - **kwargs # type: Any + 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. If the item does not already exist in the container, an exception is raised. :param item: The ID (name) or dict representing item to be replaced. - :param body: A dict-like object representing the item to replace. - :param pre_trigger_include: trigger id to be used as pre operation trigger. - :param post_trigger_include: trigger id to be used as post operation trigger. + :type item: Union[str, Dict[str, Any]] + :param Dict[str, Any] body: A dict-like object representing the item to replace. + :keyword str pre_trigger_include: trigger id to be used as pre operation trigger. + :keyword str post_trigger_include: trigger id to be used as post operation trigger. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A dict representing the item after replace went through. + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :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: The replace failed or the item with given id does not exist. - :rtype: dict[str, Any] + :returns: A dict representing the item after replace went through. + :rtype: Dict[str, Any] """ item_link = self._get_document_link(item) request_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) request_options["disableAutomaticIdGeneration"] = True + pre_trigger_include = kwargs.pop('pre_trigger_include', None) if pre_trigger_include is not None: request_options["preTriggerInclude"] = pre_trigger_include + post_trigger_include = kwargs.pop('post_trigger_include', None) if post_trigger_include is not None: request_options["postTriggerInclude"] = post_trigger_include @@ -508,26 +529,28 @@ async def replace_item( @distributed_trace_async async def delete_item( self, - item, # type: Union[str, Dict[str, Any]] - partition_key, # type: Any - pre_trigger_include=None, # type: Optional[str] - post_trigger_include=None, # type: Optional[str] - **kwargs # type: Any + item: Union[str, Dict[str, Any]], + partition_key: Union[str, int, float, bool], + **kwargs: Any ) -> None: """Delete the specified item from the container. If the item does not already exist in the container, an exception is raised. :param item: The ID (name) or dict representing item to be deleted. + :type item: Union[str, Dict[str, Any]] :param partition_key: Specifies the partition key value for the item. - :param pre_trigger_include: trigger id to be used as pre operation trigger. - :param post_trigger_include: trigger id to be used as post operation trigger. + :type partition_key: Union[str, int, float, bool] + :keyword str pre_trigger_include: trigger id to be used as pre operation trigger. + :keyword str post_trigger_include: trigger id to be used as post operation trigger. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], None], None] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The item wasn't deleted successfully. :raises ~azure.cosmos.exceptions.CosmosResourceNotFoundError: The item does not exist in the container. :rtype: None @@ -535,8 +558,10 @@ async def delete_item( request_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) request_options["partitionKey"] = self._set_partition_key(partition_key) + pre_trigger_include = kwargs.pop('pre_trigger_include', None) if pre_trigger_include is not None: request_options["preTriggerInclude"] = pre_trigger_include + post_trigger_include = kwargs.pop('post_trigger_include', None) if post_trigger_include is not None: request_options["postTriggerInclude"] = post_trigger_include @@ -546,16 +571,16 @@ async def delete_item( response_hook(self.client_connection.last_response_headers, result) @distributed_trace_async - async def read_offer(self, **kwargs): - # type: (Any) -> Offer + async def read_offer(self, **kwargs: Any) -> Offer: """Read the Offer object for this container. If no Offer already exists for the container, an exception is raised. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: Offer for the container. + :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 """ response_hook = kwargs.pop('response_hook', None) @@ -577,17 +602,17 @@ async def read_offer(self, **kwargs): return Offer(offer_throughput=offers[0]["content"]["offerThroughput"], properties=offers[0]) @distributed_trace_async - async def replace_throughput(self, throughput, **kwargs): - # type: (int, Any) -> Offer + async def replace_throughput(self, throughput: int, **kwargs: Any) -> Offer: """Replace the container's throughput. If no Offer already exists 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. + :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 """ response_hook = kwargs.pop('response_hook', None) @@ -612,17 +637,18 @@ async def replace_throughput(self, throughput, **kwargs): return Offer(offer_throughput=data["content"]["offerThroughput"], properties=data) @distributed_trace - def list_conflicts(self, max_item_count=None, **kwargs): - # type: (Optional[int], Any) -> AsyncItemPaged[Dict[str, Any]] + def list_conflicts(self, **kwargs: Any) -> AsyncItemPaged[Dict[str, Any]]: """List all the conflicts in the container. - :param max_item_count: Max number of items to be returned in the enumeration operation. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]]], None] :returns: An AsyncItemPaged of conflicts (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count @@ -636,32 +662,35 @@ def list_conflicts(self, max_item_count=None, **kwargs): @distributed_trace def query_conflicts( self, - query, # type: str - parameters=None, # type: Optional[List[Dict[str, Any]]] - partition_key=None, # type: Optional[Any] - max_item_count=None, # type: Optional[int] - **kwargs # type: Any + query: Union[str, Dict[str, Any]], + **kwargs: Any ) -> AsyncItemPaged[Dict[str, Any]]: """Return all conflicts matching a given `query`. - :param query: The Azure Cosmos DB SQL query to execute. - :param parameters: Optional array of parameters to the query. Ignored if no query is provided. - :param partition_key: Specifies the partition key value for the item. If none is passed in, a + :param Union[str, Dict[str, Any]] query: The Azure Cosmos DB SQL query to execute. + :keyword parameters: Optional array of parameters to the query. Ignored if no query is provided. + :paramtype parameters: List[Dict[str, Any]] + :keyword partition_key: Specifies the partition key value for the item. If none is passed in, a cross partition query will be executed. - :param max_item_count: Max number of items to be returned in the enumeration operation. - :keyword Callable response_hook: A callable invoked with the response metadata. + :paramtype partition_key: Union[str, int, float, bool] + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]]], None] :returns: An AsyncItemPaged of conflicts (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count + partition_key = kwargs.pop("partition_key", None) if partition_key is not None: feed_options["partitionKey"] = self._set_partition_key(partition_key) else: feed_options["enableCrossPartitionQuery"] = True + parameters = kwargs.pop('parameters', None) result = self.client_connection.QueryConflicts( collection_link=self.container_link, query=query if parameters is None else dict(query=query, parameters=parameters), @@ -675,18 +704,21 @@ def query_conflicts( @distributed_trace_async async def read_conflict( self, - conflict, # type: Union[str, Dict[str, Any]] - partition_key, # type: Any - **kwargs # type: Any + conflict: Union[str, Dict[str, Any]], + partition_key: Union[str, int, float, bool], + **kwargs: Any, ) -> Dict[str, Any]: """Get the conflict identified by `conflict`. :param conflict: The ID (name) or dict representing the conflict to retrieve. + :type conflict: Union[str, Dict[str, Any]] :param partition_key: Partition key for the conflict to retrieve. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A dict representing the retrieved conflict. + :type partition_key: Union[str, int, float, bool] + :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: The given conflict couldn't be retrieved. - :rtype: dict[str, Any] + :returns: A dict representing the retrieved conflict. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) @@ -701,17 +733,20 @@ async def read_conflict( @distributed_trace_async async def delete_conflict( self, - conflict, # type: Union[str, Dict[str, Any]] - partition_key, # type: Any - **kwargs # type: Any + conflict: Union[str, Dict[str, Any]], + partition_key: Union[str, int, float, bool], + **kwargs: Any, ) -> None: """Delete a specified conflict from the container. If the conflict does not already exist in the container, an exception is raised. - :param conflict: The ID (name) or dict representing the conflict to be deleted. - :param partition_key: Partition key for the conflict to delete. - :keyword Callable response_hook: A callable invoked with the response metadata. + :param conflict: The ID (name) or dict representing the conflict to retrieve. + :type conflict: Union[str, Dict[str, Any]] + :param partition_key: Partition key for the conflict to retrieve. + :type partition_key: Union[str, int, float, bool] + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], None], None] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The conflict wasn't deleted successfully. :raises ~azure.cosmos.exceptions.CosmosResourceNotFoundError: The conflict does not exist in the container. :rtype: None diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/database.py b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_database.py similarity index 64% rename from sdk/cosmos/azure-cosmos/azure/cosmos/aio/database.py rename to sdk/cosmos/azure-cosmos/azure/cosmos/aio/_database.py index 9561dae99192..76af33687d05 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/database.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_database.py @@ -22,7 +22,7 @@ """Interact with databases in the Azure Cosmos DB SQL API service. """ -from typing import Any, List, Dict, Union, cast, Optional +from typing import Any, Dict, Union, cast import warnings from azure.core.async_paging import AsyncItemPaged @@ -31,15 +31,17 @@ from ._cosmos_client_connection_async import CosmosClientConnection from .._base import build_options as _build_options -from .container import ContainerProxy +from ._container import ContainerProxy from ..offer import Offer from ..http_constants import StatusCodes from ..exceptions import CosmosResourceNotFoundError -from .user import UserProxy +from ._user import UserProxy from ..documents import IndexingMode +from ..partition_key import PartitionKey __all__ = ("DatabaseProxy",) + # pylint: disable=protected-access # pylint: disable=missing-client-constructor-parameter-credential,missing-client-constructor-parameter-kwargs @@ -47,7 +49,9 @@ class DatabaseProxy(object): """An interface to interact with a specific database. This class should not be instantiated directly. Instead use the - :func:`CosmosClient.get_database_client` method. + :func:`~azure.cosmos.aio.cosmos_client.CosmosClient.get_database_client` method to get an existing + database, or the :func:`~azure.cosmos.aio.cosmos_client.CosmosClient.create_database` method to create + a new database. A database contains one or more containers, each of which can contain items, stored procedures, triggers, and user-defined functions. @@ -69,10 +73,15 @@ class DatabaseProxy(object): * `_users`: The addressable path of the users resource. """ - def __init__(self, client_connection, id, properties=None): # pylint: disable=redefined-builtin - # type: (CosmosClientConnection, str, Dict[str, Any]) -> None + def __init__( + self, + client_connection: CosmosClientConnection, + id: str, # pylint: disable=redefined-builtin + properties: Dict[str, Any] = None + ) -> None: """ - :param ClientSession client_connection: Client from which this database was retrieved. + :param client_connection: Client from which this database was retrieved. + :type client_connection: ~azure.cosmos.aio.CosmosClientConnection :param str id: ID (name) of the database. """ self.client_connection = client_connection @@ -80,13 +89,11 @@ def __init__(self, client_connection, id, properties=None): # pylint: disable=r self.database_link = u"dbs/{}".format(self.id) self._properties = properties - def __repr__(self): - # type () -> str + def __repr__(self) -> str: return "".format(self.database_link)[:1024] @staticmethod - def _get_container_id(container_or_id): - # type: (Union[str, ContainerProxy, Dict[str, Any]]) -> str + def _get_container_id(container_or_id: Union[str, ContainerProxy, Dict[str, Any]]) -> str: if isinstance(container_or_id, str): return container_or_id try: @@ -95,12 +102,10 @@ def _get_container_id(container_or_id): pass return cast("Dict[str, str]", container_or_id)["id"] - def _get_container_link(self, container_or_id): - # type: (Union[str, ContainerProxy, Dict[str, Any]]) -> str + def _get_container_link(self, container_or_id: Union[str, ContainerProxy, Dict[str, Any]]) -> str: return u"{}/colls/{}".format(self.database_link, self._get_container_id(container_or_id)) - def _get_user_link(self, user_or_id): - # type: (Union[UserProxy, str, Dict[str, Any]]) -> str + def _get_user_link(self, user_or_id: Union[UserProxy, str, Dict[str, Any]]) -> str: if isinstance(user_or_id, str): return u"{}/users/{}".format(self.database_link, user_or_id) try: @@ -109,22 +114,22 @@ def _get_user_link(self, user_or_id): pass return u"{}/users/{}".format(self.database_link, cast("Dict[str, str]", user_or_id)["id"]) - async def _get_properties(self): - # type: () -> Dict[str, Any] + async def _get_properties(self) -> Dict[str, Any]: if self._properties is None: self._properties = await self.read() return self._properties @distributed_trace_async - async def read(self, **kwargs): - # type: (Optional[bool], Any) -> Dict[str, Any] + async def read(self, **kwargs: Any) -> Dict[str, Any]: """Read the database properties. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. - :keyword Callable response_hook: A callable invoked with the response metadata. - :rtype: Dict[Str, Any] + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. + :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 the given database couldn't be retrieved. + :returns: A dict representing the database properties + :rtype: Dict[str, Any] """ # TODO this helper function should be extracted from CosmosClient from .cosmos_client import CosmosClient @@ -144,40 +149,38 @@ async def read(self, **kwargs): @distributed_trace_async async def create_container( - self, - id, # type: str # pylint: disable=redefined-builtin - partition_key, # type: Any - indexing_policy=None, # type: Optional[Dict[str, Any]] - default_ttl=None, # type: Optional[int] - offer_throughput=None, # type: Optional[int] - unique_key_policy=None, # type: Optional[Dict[str, Any]] - conflict_resolution_policy=None, # type: Optional[Dict[str, Any]] - **kwargs # type: Any - ): - # type: (...) -> ContainerProxy + self, + id: str, # pylint: disable=redefined-builtin + partition_key: PartitionKey, + **kwargs: Any + ) -> ContainerProxy: """Create a new container with the given ID (name). If a container with the given ID already exists, a CosmosResourceExistsError is raised. - :param id: ID (name) of container to create. + :param str id: ID (name) of container to create. :param partition_key: The partition key to use for the container. - :param indexing_policy: The indexing policy to apply to the container. - :param default_ttl: Default time to live (TTL) for items in the container. If unspecified, items do not expire. - :param offer_throughput: The provisioned throughput for this offer. - :param unique_key_policy: The unique key policy to apply to the container. - :param conflict_resolution_policy: The conflict resolution policy to apply to the container. + :type partition_key: ~azure.cosmos.partition_key.PartitionKey + :keyword Dict[str, str] indexing_policy: The indexing policy to apply to the container. + :keyword int default_ttl: Default time to live (TTL) for items in the container. + If unspecified, items do not expire. + :keyword int offer_throughput: The provisioned throughput for this offer. + :keyword Dict[str, str] unique_key_policy: The unique key policy to apply to the container. + :keyword Dict[str, str] conflict_resolution_policy: The conflict resolution policy to apply to the container. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword Callable response_hook: A callable invoked with the response metadata. - :keyword analytical_storage_ttl: Analytical store time to live (TTL) for items in the container. A value of + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], Dict[str, Any]], None] + :keyword int analytical_storage_ttl: Analytical store time to live (TTL) for items in the container. A value of None leaves analytical storage off and a value of -1 turns analytical storage on with no TTL. Please note that analytical storage can only be enabled on Synapse Link enabled accounts. - :returns: A `ContainerProxy` instance representing the new container. :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The container creation failed. - :rtype: ~azure.cosmos.ContainerProxy + :returns: A `ContainerProxy` instance representing the new container. + :rtype: ~azure.cosmos.aio.ContainerProxy .. admonition:: Example: @@ -197,9 +200,10 @@ async def create_container( :caption: Create a container with specific settings; in this case, a custom partition key: :name: create_container_with_settings """ - definition = dict(id=id) # type: Dict[str, Any] + definition: Dict[str, Any] = dict(id=id) if partition_key is not None: definition["partitionKey"] = partition_key + indexing_policy = kwargs.pop('indexing_policy', None) if indexing_policy is not None: if indexing_policy.get("indexingMode") is IndexingMode.Lazy: warnings.warn( @@ -207,19 +211,22 @@ async def create_container( DeprecationWarning ) definition["indexingPolicy"] = indexing_policy + default_ttl = kwargs.pop('default_ttl', None) if default_ttl is not None: definition["defaultTtl"] = default_ttl + unique_key_policy = kwargs.pop('unique_key_policy', None) if unique_key_policy is not None: definition["uniqueKeyPolicy"] = unique_key_policy + conflict_resolution_policy = kwargs.pop('conflict_resolution_policy', None) if conflict_resolution_policy is not None: definition["conflictResolutionPolicy"] = conflict_resolution_policy - analytical_storage_ttl = kwargs.pop("analytical_storage_ttl", None) if analytical_storage_ttl is not None: definition["analyticalStorageTtl"] = analytical_storage_ttl request_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + offer_throughput = kwargs.pop('offer_throughput', None) if offer_throughput is not None: request_options["offerThroughput"] = offer_throughput @@ -234,50 +241,54 @@ async def create_container( @distributed_trace_async async def create_container_if_not_exists( - self, - id, # type: str # pylint: disable=redefined-builtin - partition_key, # type: Any - indexing_policy=None, # type: Optional[Dict[str, Any]] - default_ttl=None, # type: Optional[int] - offer_throughput=None, # type: Optional[int] - unique_key_policy=None, # type: Optional[Dict[str, Any]] - conflict_resolution_policy=None, # type: Optional[Dict[str, Any]] - **kwargs # type: Any - ): - # type: (...) -> ContainerProxy + self, + id: str, # pylint: disable=redefined-builtin + partition_key: PartitionKey, + **kwargs: Any + ) -> ContainerProxy: """Create a container if it does not exist already. If the container already exists, the existing settings are returned. Note: it does not check or update the existing container settings or offer throughput if they differ from what was passed into the method. - :param id: ID (name) of container to read or create. + :param str id: ID (name) of container to create. :param partition_key: The partition key to use for the container. - :param indexing_policy: The indexing policy to apply to the container. - :param default_ttl: Default time to live (TTL) for items in the container. If unspecified, items do not expire. - :param offer_throughput: The provisioned throughput for this offer. - :param unique_key_policy: The unique key policy to apply to the container. - :param conflict_resolution_policy: The conflict resolution policy to apply to the container. + :type partition_key: ~azure.cosmos.partition_key.PartitionKey + :keyword Dict[str, str] indexing_policy: The indexing policy to apply to the container. + :keyword int default_ttl: Default time to live (TTL) for items in the container. + If unspecified, items do not expire. + :keyword int offer_throughput: The provisioned throughput for this offer. + :keyword Dict[str, str] unique_key_policy: The unique key policy to apply to the container. + :keyword Dict[str, str] conflict_resolution_policy: The conflict resolution policy to apply to the container. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword Callable response_hook: A callable invoked with the response metadata. - :keyword analytical_storage_ttl: Analytical store time to live (TTL) for items in the container. A value of - None leaves analytical storage off and a value of -1 turns analytical storage on with no TTL. Please + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], Dict[str, Any]], None] + :keyword int analytical_storage_ttl: Analytical store time to live (TTL) for items in the container. A value of + None leaves analytical storage off and a value of -1 turns analytical storage on with no TTL. Please note that analytical storage can only be enabled on Synapse Link enabled accounts. - :returns: A `ContainerProxy` instance representing the container. - :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The container read or creation failed. - :rtype: ~azure.cosmos.ContainerProxy + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The container creation failed. + :returns: A `ContainerProxy` instance representing the new container. + :rtype: ~azure.cosmos.aio.ContainerProxy """ - analytical_storage_ttl = kwargs.pop("analytical_storage_ttl", None) try: container_proxy = self.get_container_client(id) await container_proxy.read(**kwargs) return container_proxy except CosmosResourceNotFoundError: + indexing_policy = kwargs.pop('indexing_policy', None) + default_ttl = kwargs.pop('default_ttl', None) + unique_key_policy = kwargs.pop('unique_key_policy', None) + conflict_resolution_policy = kwargs.pop('conflict_resolution_policy', None) + analytical_storage_ttl = kwargs.pop("analytical_storage_ttl", None) + offer_throughput = kwargs.pop('offer_throughput', None) + response_hook = kwargs.pop('response_hook', None) return await self.create_container( id=id, partition_key=partition_key, @@ -286,16 +297,18 @@ async def create_container_if_not_exists( offer_throughput=offer_throughput, unique_key_policy=unique_key_policy, conflict_resolution_policy=conflict_resolution_policy, - analytical_storage_ttl=analytical_storage_ttl + analytical_storage_ttl=analytical_storage_ttl, + response_hook=response_hook ) - def get_container_client(self, container): - # type: (Union[str, ContainerProxy, Dict[str, Any]]) -> ContainerProxy + def get_container_client(self, container: Union[str, ContainerProxy, Dict[str, Any]]) -> ContainerProxy: """Get a `ContainerProxy` for a container with specified ID (name). - :param container: The ID (name) of the container to be retrieved. + :param container: The ID (name), dict representing the properties, or :class:`ContainerProxy` + instance of the container to get. + :type container: Union[str, Dict[str, Any], ~azure.cosmos.aio.ContainerProxy] :returns: A `ContainerProxy` instance representing the container. - :rtype: ~azure.cosmos.ContainerProxy + :rtype: ~azure.cosmos.aio.ContainerProxy .. admonition:: Example: @@ -320,19 +333,18 @@ def get_container_client(self, container): @distributed_trace def list_containers( - self, - max_item_count=None, - **kwargs - ): - # type: (Optional[int], Optional[bool], Any) -> AsyncItemPaged[Dict[str, Any]] + self, + **kwargs + ) -> AsyncItemPaged[Dict[str, Any]]: """List the containers in the database. - :param max_item_count: Max number of items to be returned in the enumeration operation. + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]]], None] :returns: An AsyncItemPaged of container properties (dicts). - :rtype: AsyncItemPaged[dict[str, Any]] + :rtype: AsyncItemPaged[Dict[str, Any]] .. admonition:: Example: @@ -346,6 +358,7 @@ def list_containers( """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count @@ -358,31 +371,31 @@ def list_containers( @distributed_trace def query_containers( - self, - query=None, # type: Optional[str] - parameters=None, # type: Optional[List[Dict[str, Any]]] - max_item_count=None, # type: Optional[int] - **kwargs # type: Any - ): - # type: (...) -> AsyncItemPaged[Dict[str, Any]] + self, + **kwargs: Any + ) -> AsyncItemPaged[Dict[str, Any]]: """List the properties for containers in the current database. - :param query: The Azure Cosmos DB SQL query to execute. - :param parameters: Optional array of parameters to the query. + :keyword Union[str, Dict[str, Any]] query: The Azure Cosmos DB SQL query to execute. + :keyword parameters: Optional array of parameters to the query. Each parameter is a dict() with 'name' and 'value' keys. - Ignored if no query is provided. - :param max_item_count: Max number of items to be returned in the enumeration operation. + :paramtype parameters: Optional[List[Dict[str, Any]]] + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]]], None] :returns: An AsyncItemPaged of container properties (dicts). - :rtype: AsyncItemPaged[dict[str, Any]] + :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count + parameters = kwargs.pop('parameters', None) + query = kwargs.pop('query', None) result = self.client_connection.QueryContainers( database_link=self.database_link, query=query if parameters is None else dict(query=query, parameters=parameters), @@ -395,15 +408,12 @@ def query_containers( @distributed_trace_async async def replace_container( - self, - container, # type: Union[str, ContainerProxy, Dict[str, Any]] - partition_key, # type: Any - indexing_policy=None, # type: Optional[Dict[str, Any]] - default_ttl=None, # type: Optional[int] - conflict_resolution_policy=None, # type: Optional[Dict[str, Any]] - **kwargs # type: Any - ): - # type: (...) -> ContainerProxy + 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 + ) -> ContainerProxy: """Reset the properties of the container. Property changes are persisted immediately. Any properties not specified @@ -411,21 +421,25 @@ async def replace_container( :param container: The ID (name), dict representing the properties or :class:`ContainerProxy` instance of the container to be replaced. + :type container: Union[str, Dict[str, Any], ~azure.cosmos.aio.ContainerProxy] :param partition_key: The partition key to use for the container. - :param indexing_policy: The indexing policy to apply to the container. - :param default_ttl: Default time to live (TTL) for items in the container. + :type partition_key: ~azure.cosmos.partition_key.PartitionKey + :keyword Dict[str, str] indexing_policy: The indexing policy to apply to the container. + :keyword int default_ttl: Default time to live (TTL) for items in the container. If unspecified, items do not expire. - :param conflict_resolution_policy: The conflict resolution policy to apply to the container. + :keyword Dict[str, str] conflict_resolution_policy: The conflict resolution policy to apply to the container. :keyword str session_token: Token for use with Session consistency. :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. + :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: Raised if the container couldn't be replaced. This includes if the container with given id does not exist. :returns: A `ContainerProxy` instance representing the container after replace completed. - :rtype: ~azure.cosmos.ContainerProxy + :rtype: ~azure.cosmos.aio.ContainerProxy .. admonition:: Example: @@ -442,6 +456,9 @@ async def replace_container( container_id = self._get_container_id(container) container_link = self._get_container_link(container_id) + indexing_policy = kwargs.pop('indexing_policy', None) + default_ttl = kwargs.pop('default_ttl', None) + conflict_resolution_policy = kwargs.pop('conflict_resolution_policy', None) parameters = { key: value for key, value in { @@ -467,22 +484,24 @@ async def replace_container( @distributed_trace_async async def delete_container( - self, - container, # type: Union[str, ContainerProxy, Dict[str, Any]] - **kwargs # type: Any - ): - # type: (...) -> None + self, + container: Union[str, ContainerProxy, Dict[str, Any]], + **kwargs: Any + ) -> None: """Delete a container. :param container: The ID (name) of the container to delete. You can either pass in the ID of the container to delete, a :class:`ContainerProxy` instance or a dict representing the properties of the container. + :type container: str or Dict[str, Any] or ~azure.cosmos.aio.ContainerProxy :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], None], None] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the container couldn't be deleted. :rtype: None """ @@ -495,19 +514,19 @@ async def delete_container( response_hook(self.client_connection.last_response_headers, result) @distributed_trace_async - async def create_user(self, body, **kwargs): - # type: (Dict[str, Any], Any) -> UserProxy + async def create_user(self, body: Dict[str, Any], **kwargs: Any) -> UserProxy: # body should just be id? """Create a new user in the container. To update or replace an existing user, use the :func:`ContainerProxy.upsert_user` method. - :param body: A dict-like object with an `id` key and value representing the user to be created. + :param Dict[str, Any] body: A dict-like object with an `id` key and value representing the user to be created. The user ID must be unique within the database, and consist of no more than 255 characters. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A `UserProxy` instance representing the new user. + :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 the given user couldn't be created. - :rtype: ~azure.cosmos.UserProxy + :returns: A `UserProxy` instance representing the new user. + :rtype: ~azure.cosmos.aio.UserProxy .. admonition:: Example: @@ -532,29 +551,38 @@ async def create_user(self, body, **kwargs): client_connection=self.client_connection, id=user["id"], database_link=self.database_link, properties=user ) - def get_user_client(self, user_id): - # type: (str) -> UserProxy + def get_user_client(self, user: Union[str, UserProxy, Dict[str, Any]]) -> UserProxy: """Get a `UserProxy` for a user with specified ID. - :param user: The ID (name) of the user to be retrieved. + :param user: The ID (name), dict representing the properties, or :class:`UserProxy` + instance of the user to get. + :type user: Union[str, Dict[str, Any], ~azure.cosmos.aio.UserProxy] :returns: A `UserProxy` instance representing the retrieved user. - :rtype: ~azure.cosmos.UserProxy + :rtype: ~azure.cosmos.aio.UserProxy """ + try: + id_value = user.id + except AttributeError: + try: + id_value = user['id'] + except TypeError: + id_value = user - return UserProxy(client_connection=self.client_connection, id=user_id, database_link=self.database_link) + return UserProxy(client_connection=self.client_connection, id=id_value, database_link=self.database_link) @distributed_trace - def list_users(self, max_item_count=None, **kwargs): - # type: (Optional[int], Any) -> AsyncItemPaged[Dict[str, Any]] + def list_users(self, **kwargs: Any) -> AsyncItemPaged[Dict[str, Any]]: """List all the users in the container. - :param max_item_count: Max number of users to be returned in the enumeration operation. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword int max_item_count: Max number of users to be returned in the enumeration operation. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]]], None] :returns: An AsyncItemPaged of user properties (dicts). - :rtype: AsyncItemPaged[dict[str, Any]] + :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count @@ -567,29 +595,30 @@ def list_users(self, max_item_count=None, **kwargs): @distributed_trace def query_users( - self, - query, # type: str - parameters=None, # type: Optional[List[Dict[str, Any]]] - max_item_count=None, # type: Optional[int] - **kwargs # type: Any - ): - # type: (...) -> AsyncItemPaged[Dict[str, Any]] + self, + query: Union[str, Dict[str, Any]], + **kwargs: Any + ) -> AsyncItemPaged[Dict[str, Any]]: """Return all users matching the given `query`. - :param query: The Azure Cosmos DB SQL query to execute. - :param parameters: Optional array of parameters to the query. + :param Union[str, Dict[str, Any]] query: The Azure Cosmos DB SQL query to execute. + :keyword parameters: Optional array of parameters to the query. Each parameter is a dict() with 'name' and 'value' keys. Ignored if no query is provided. - :param max_item_count: Max number of users to be returned in the enumeration operation. - :keyword Callable response_hook: A callable invoked with the response metadata. + :paramtype parameters: Optional[List[Dict[str, Any]]] + :keyword int max_item_count: Max number of users to be returned in the enumeration operation. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]]], None] :returns: An AsyncItemPaged of user properties (dicts). - :rtype: AsyncItemPaged[str, Any] + :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count + parameters = kwargs.pop('parameters', None) result = self.client_connection.QueryUsers( database_link=self.database_link, query=query if parameters is None else dict(query=query, parameters=parameters), @@ -601,18 +630,18 @@ def query_users( return result @distributed_trace_async - async def upsert_user(self, body, **kwargs): - # type: (Dict[str, Any], Any) -> UserProxy + async def upsert_user(self, body: Dict[str, Any], **kwargs: Any) -> UserProxy: """Insert or update the specified user. If the user already exists in the container, it is replaced. If the user does not already exist, it is inserted. - :param body: A dict-like object representing the user to update or insert. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A `UserProxy` instance representing the upserted user. + :param Dict[str, Any] body: A dict-like object representing the user to update or insert. + :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 the given user could not be upserted. - :rtype: ~azure.cosmos.UserProxy + :returns: A `UserProxy` instance representing the upserted user. + :rtype: ~azure.cosmos.aio.UserProxy """ request_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) @@ -630,29 +659,29 @@ async def upsert_user(self, body, **kwargs): @distributed_trace_async async def replace_user( - self, - user, # type: Union[str, UserProxy, Dict[str, Any]] - body, # type: Dict[str, Any] - **kwargs # type: Any - ): - # type: (...) -> UserProxy + self, + user: Union[str, UserProxy, Dict[str, Any]], + body: Dict[str, Any], + **kwargs: Any + ) -> UserProxy: """Replaces the specified user if it exists in the container. :param user: The ID (name), dict representing the properties or :class:`UserProxy` instance of the user to be replaced. - :param body: A dict-like object representing the user to replace. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A `UserProxy` instance representing the user after replace went through. + :type user: Union[str, Dict[str, Any], ~azure.cosmos.aio.UserProxy] + :param Dict[str, Any] body: A dict-like object representing the user to replace. + :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 the replace failed or the user with given ID does not exist. - :rtype: ~azure.cosmos.UserProxy + :returns: A `UserProxy` instance representing the user after replace went through. + :rtype: ~azure.cosmos.aio.UserProxy """ request_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) - replaced_user = await self.client_connection.ReplaceUser( - user_link=self._get_user_link(user), user=body, options=request_options, **kwargs - ) # type: Dict[str, str] + replaced_user: Dict[str, Any] = await self.client_connection.ReplaceUser( + user_link=self._get_user_link(user), user=body, options=request_options, **kwargs) if response_hook: response_hook(self.client_connection.last_response_headers, replaced_user) @@ -665,13 +694,14 @@ async def replace_user( ) @distributed_trace_async - async def delete_user(self, user, **kwargs): - # type: (Union[str, UserProxy, Dict[str, Any]], Any) -> None + async def delete_user(self, user: Union[str, UserProxy, Dict[str, Any]], **kwargs: Any) -> None: """Delete the specified user from the container. :param user: The ID (name), dict representing the properties or :class:`UserProxy` instance of the user to be deleted. - :keyword Callable response_hook: A callable invoked with the response metadata. + :type user: Union[str, Dict[str, Any], ~azure.cosmos.aio.UserProxy] + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], None], None] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The user wasn't deleted successfully. :raises ~azure.cosmos.exceptions.CosmosResourceNotFoundError: The user does not exist in the container. :rtype: None @@ -686,14 +716,14 @@ async def delete_user(self, user, **kwargs): response_hook(self.client_connection.last_response_headers, result) @distributed_trace_async - async def read_offer(self, **kwargs): - # type: (Any) -> Offer + async def read_offer(self, **kwargs: Any) -> Offer: """Read the Offer object for this database. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: Offer for the database. + :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 """ response_hook = kwargs.pop('response_hook', None) @@ -715,15 +745,15 @@ async def read_offer(self, **kwargs): return Offer(offer_throughput=offers[0]["content"]["offerThroughput"], properties=offers[0]) @distributed_trace_async - async def replace_throughput(self, throughput, **kwargs): - # type: (Optional[int], Any) -> Offer + async def replace_throughput(self, throughput: int, **kwargs: Any) -> Offer: """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. + :param int throughput: The throughput to be set. + :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 """ response_hook = kwargs.pop('response_hook', None) diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/scripts.py b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_scripts.py similarity index 66% rename from sdk/cosmos/azure-cosmos/azure/cosmos/aio/scripts.py rename to sdk/cosmos/azure-cosmos/azure/cosmos/aio/_scripts.py index 35aba7065e55..bccba99b38ac 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/scripts.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_scripts.py @@ -22,13 +22,13 @@ """Create, read, update and delete and execute scripts in the Azure Cosmos DB SQL API service. """ -from typing import Any, List, Dict, Union, Optional +from typing import Any, Dict, Union from azure.core.async_paging import AsyncItemPaged from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.tracing.decorator import distributed_trace -from azure.cosmos.aio._cosmos_client_connection_async import CosmosClientConnection as _cosmos_client_connection +from ._cosmos_client_connection_async import CosmosClientConnection as _CosmosClientConnection from .._base import build_options as _build_options from ..partition_key import NonePartitionKeyValue @@ -49,28 +49,34 @@ class ScriptsProxy(object): :func:`ContainerProxy.scripts` attribute. """ - def __init__(self, container, client_connection, container_link): - # type: (ContainerProxy, CosmosClientConnection, str) -> None + def __init__( + self, + container: "ContainerProxy", + client_connection: _CosmosClientConnection, + container_link: str + ) -> None: self.client_connection = client_connection self.container_link = container_link self.container_proxy = container - def _get_resource_link(self, script_or_id, typ): - # type: (Union[Dict[str, Any], str], str) -> str + def _get_resource_link(self, script_or_id: Union[Dict[str, Any], str], typ: str) -> str: if isinstance(script_or_id, str): return u"{}/{}/{}".format(self.container_link, typ, script_or_id) return script_or_id["_self"] @distributed_trace - def list_stored_procedures(self, max_item_count=None, **kwargs): - # type: (Optional[int], Any) -> AsyncItemPaged[Dict[str, Any]] + def list_stored_procedures( + self, + **kwargs: Any + ) -> AsyncItemPaged[Dict[str, Any]]: """List all stored procedures in the container. - :param int max_item_count: Max number of items to be returned in the enumeration operation. + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :returns: An AsyncItemPaged of stored procedures (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count @@ -81,24 +87,24 @@ def list_stored_procedures(self, max_item_count=None, **kwargs): @distributed_trace def query_stored_procedures( self, - query, - parameters=None, - max_item_count=None, - **kwargs - ): - # type: (str, Optional[List[str]], Optional[int], Any) -> AsyncItemPaged[Dict[str, Any]] + query: Union[str, Dict[str, Any]], + **kwargs: Any + ) -> AsyncItemPaged[Dict[str, Any]]: """Return all stored procedures matching the given `query`. - :param query: The Azure Cosmos DB SQL query to execute. - :param parameters: Optional array of parameters to the query. Ignored if no query is provided. - :param max_item_count: Max number of items to be returned in the enumeration operation. + :param Union[str, Dict[str, Any]] query: The Azure Cosmos DB SQL query to execute. + :keyword parameters: Optional array of parameters to the query. Ignored if no query is provided. + :paramtype parameters: Optional[List[str]] + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :returns: An AsyncItemPaged of stored procedures (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count + parameters = kwargs.pop('parameters', None) return self.client_connection.QueryStoredProcedures( collection_link=self.container_link, query=query if parameters is None else dict(query=query, parameters=parameters), @@ -107,14 +113,14 @@ def query_stored_procedures( ) @distributed_trace_async - async def get_stored_procedure(self, sproc, **kwargs): - # type: (Union[str, Dict[str, Any]], Any) -> Dict[str, Any] - """Get the stored procedure identified by `id`. + async def get_stored_procedure(self, sproc: Union[str, Dict[str, Any]], **kwargs: Any) -> Dict[str, Any]: + """Get the stored procedure identified by `sproc`. - :param sproc: The ID (name) or dict representing stored procedure to retrieve. - :returns: A dict representing the retrieved stored procedure. + :param sproc: The ID (name) or dict representing the stored procedure to retrieve. + :type sproc: Union[str, Dict[str, Any]] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the given stored procedure couldn't be retrieved. - :rtype: dict[str, Any] + :returns: A dict representing the retrieved stored procedure. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) @@ -123,16 +129,15 @@ async def get_stored_procedure(self, sproc, **kwargs): ) @distributed_trace_async - async def create_stored_procedure(self, body, **kwargs): - # type: (Dict[str, Any], Any) -> Dict[str, Any] + async def create_stored_procedure(self, body: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: """Create a new stored procedure in the container. - To replace an existing sproc, use the :func:`Container.scripts.replace_stored_procedure` method. + To replace an existing stored procedure, use the :func:`Container.scripts.replace_stored_procedure` method. - :param body: A dict-like object representing the sproc to create. - :returns: A dict representing the new stored procedure. + :param Dict[str, Any] body: A dict-like object representing the stored procedure to create. :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the given stored procedure couldn't be created. - :rtype: dict[str, Any] + :returns: A dict representing the new stored procedure. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) @@ -143,21 +148,21 @@ async def create_stored_procedure(self, body, **kwargs): @distributed_trace_async async def replace_stored_procedure( self, - sproc, - body, - **kwargs - ): - # type: (Union[str, Dict[str, Any]], Dict[str, Any], Any) -> Dict[str, Any] + sproc: Union[str, Dict[str, Any]], + body: Dict[str, Any], + **kwargs: Any + ) -> Dict[str, Any]: """Replace a specified stored procedure in the container. If the stored procedure does not already exist in the container, an exception is raised. :param sproc: The ID (name) or dict representing stored procedure to be replaced. - :param body: A dict-like object representing the sproc to replace. - :returns: A dict representing the stored procedure after replace went through. + :type sproc: Union[str, Dict[str, Any]] + :param Dict[str, Any] body: A dict-like object representing the stored procedure to replace. :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the replace failed or the stored procedure with given id does not exist. - :rtype: dict[str, Any] + :returns: A dict representing the stored procedure after replace went through. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) @@ -169,15 +174,16 @@ async def replace_stored_procedure( ) @distributed_trace_async - async def delete_stored_procedure(self, sproc, **kwargs): - # type: (Union[str, Dict[str, Any]], Any) -> None + async def delete_stored_procedure(self, sproc: Union[str, Dict[str, Any]], **kwargs: Any) -> None: """Delete a specified stored procedure from the container. If the stored procedure does not already exist in the container, an exception is raised. :param sproc: The ID (name) or dict representing stored procedure to be deleted. - :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The sproc wasn't deleted successfully. - :raises ~azure.cosmos.exceptions.CosmosResourceNotFoundError: The sproc does not exist in the container. + :type sproc: Union[str, Dict[str, Any]] + :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The stored procedure wasn't deleted successfully. + :raises ~azure.cosmos.exceptions.CosmosResourceNotFoundError: The stored procedure does not exist in + the container. :rtype: None """ request_options = _build_options(kwargs) @@ -189,55 +195,58 @@ async def delete_stored_procedure(self, sproc, **kwargs): @distributed_trace_async async def execute_stored_procedure( self, - sproc, # type: Union[str, Dict[str, Any]] - partition_key=None, # type: Optional[str] - params=None, # type: Optional[List[Any]] - enable_script_logging=None, # type: Optional[bool] - **kwargs # type: Any - ): - # type: (...) -> Any + sproc: Union[str, Dict[str, Any]], + **kwargs: Any + ) -> Dict[str, Any]: """Execute a specified stored procedure. If the stored procedure does not already exist in the container, an exception is raised. :param sproc: The ID (name) or dict representing the stored procedure to be executed. - :param partition_key: Specifies the partition key to indicate which partition the sproc should execute on. - :param params: List of parameters to be passed to the stored procedure to be executed. - :param bool enable_script_logging: Enables or disables script logging for the current request. - :returns: Result of the executed stored procedure for the given parameters. + :type sproc: Union[str, Dict[str, Any]] + :keyword partition_key: Specifies the partition key to indicate which partition the stored procedure should + execute on. + :paramtype partition_key: Union[str, int, float, bool] + :keyword parameters: List of parameters to be passed to the stored procedure to be executed. + :paramtype parameters: List[Dict[str, Any]] + :keyword bool enable_script_logging: Enables or disables script logging for the current request. :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the stored procedure execution failed or if the stored procedure with given id does not exists in the container. - :rtype: dict[str, Any] + :returns: Result of the executed stored procedure for the given parameters. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) + partition_key = kwargs.pop("partition_key", None) if partition_key is not None: request_options["partitionKey"] = ( - _cosmos_client_connection._return_undefined_or_empty_partition_key( + _CosmosClientConnection._return_undefined_or_empty_partition_key( await self.container_proxy.is_system_key) if partition_key == NonePartitionKeyValue else partition_key ) + enable_script_logging = kwargs.pop('enable_script_logging', None) if enable_script_logging is not None: request_options["enableScriptLogging"] = enable_script_logging + parameters = kwargs.pop("parameters", None) return await self.client_connection.ExecuteStoredProcedure( sproc_link=self._get_resource_link(sproc, ScriptType.StoredProcedure), - params=params, + params=parameters, options=request_options, **kwargs ) @distributed_trace - def list_triggers(self, max_item_count=None, **kwargs): - # type: (Optional[int], Any) -> AsyncItemPaged[Dict[str, Any]] + def list_triggers(self, **kwargs: Any) -> AsyncItemPaged[Dict[str, Any]]: """List all triggers in the container. - :param max_item_count: Max number of items to be returned in the enumeration operation. + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :returns: An AsyncItemPaged of triggers (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count @@ -246,20 +255,26 @@ def list_triggers(self, max_item_count=None, **kwargs): ) @distributed_trace - def query_triggers(self, query, parameters=None, max_item_count=None, **kwargs): - # type: (str, Optional[List[str]], Optional[int], Any) -> AsyncItemPaged[Dict[str, Any]] + def query_triggers( + self, + query: Union[str, Dict[str, Any]], + **kwargs: Any + ) -> AsyncItemPaged[Dict[str, Any]]: """Return all triggers matching the given `query`. - :param query: The Azure Cosmos DB SQL query to execute. - :param parameters: Optional array of parameters to the query. Ignored if no query is provided. - :param max_item_count: Max number of items to be returned in the enumeration operation. + :param Union[str, Dict[str, Any]] query: The Azure Cosmos DB SQL query to execute. + :keyword parameters: Optional array of parameters to the query. Ignored if no query is provided. + :paramtype parameters: Optional[List[Dict[str, Any]]] + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :returns: An AsyncItemPaged of triggers (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count + parameters = kwargs.pop('parameters', None) return self.client_connection.QueryTriggers( collection_link=self.container_link, query=query if parameters is None else dict(query=query, parameters=parameters), @@ -268,14 +283,14 @@ def query_triggers(self, query, parameters=None, max_item_count=None, **kwargs): ) @distributed_trace_async - async def get_trigger(self, trigger, **kwargs): - # type: (Union[str, Dict[str, Any]], Any) -> Dict[str, Any] + async def get_trigger(self, trigger: Union[str, Dict[str, Any]], **kwargs: Any) -> Dict[str, Any]: """Get a trigger identified by `id`. :param trigger: The ID (name) or dict representing trigger to retrieve. - :returns: A dict representing the retrieved trigger. + :type trigger: Union[str, Dict[str, Any]] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the given trigger couldn't be retrieved. - :rtype: dict[str, Any] + :returns: A dict representing the retrieved trigger. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) @@ -284,16 +299,15 @@ async def get_trigger(self, trigger, **kwargs): ) @distributed_trace_async - async def create_trigger(self, body, **kwargs): - # type: (Dict[str, Any], Any) -> Dict[str, Any] + async def create_trigger(self, body: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: """Create a trigger in the container. To replace an existing trigger, use the :func:`ContainerProxy.scripts.replace_trigger` method. - :param body: A dict-like object representing the trigger to create. - :returns: A dict representing the new trigger. + :param Dict[str, Any] body: A dict-like object representing the trigger to create. :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the given trigger couldn't be created. - :rtype: dict[str, Any] + :returns: A dict representing the new trigger. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) @@ -302,18 +316,23 @@ async def create_trigger(self, body, **kwargs): ) @distributed_trace_async - async def replace_trigger(self, trigger, body, **kwargs): - # type: (Union[str, Dict[str, Any]], Dict[str, Any], Any) -> Dict[str, Any] + async def replace_trigger( + self, + trigger: Union[str, Dict[str, Any]], + body: Dict[str, Any], + **kwargs: Any + ) -> Dict[str, Any]: """Replace a specified trigger in the container. If the trigger does not already exist in the container, an exception is raised. :param trigger: The ID (name) or dict representing trigger to be replaced. - :param body: A dict-like object representing the trigger to replace. - :returns: A dict representing the trigger after replace went through. + :type trigger: Union[str, Dict[str, Any]] + :param Dict[str, Any] body: A dict-like object representing the trigger to replace. :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the replace failed or the trigger with given id does not exist. - :rtype: dict[str, Any] + :returns: A dict representing the trigger after replace went through. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) @@ -325,13 +344,13 @@ async def replace_trigger(self, trigger, body, **kwargs): ) @distributed_trace_async - async def delete_trigger(self, trigger, **kwargs): - # type: (Union[str, Dict[str, Any]], Any) -> None + async def delete_trigger(self, trigger: Union[str, Dict[str, Any]], **kwargs: Any) -> None: """Delete a specified trigger from the container. If the trigger does not already exist in the container, an exception is raised. :param trigger: The ID (name) or dict representing trigger to be deleted. + :type trigger: Union[str, Dict[str, Any]] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The trigger wasn't deleted successfully. :raises ~azure.cosmos.exceptions.CosmosResourceNotFoundError: The trigger does not exist in the container. :rtype: None @@ -343,15 +362,18 @@ async def delete_trigger(self, trigger, **kwargs): ) @distributed_trace - def list_user_defined_functions(self, max_item_count=None, **kwargs): - # type: (Optional[int], Any) -> AsyncItemPaged[Dict[str, Any]] + def list_user_defined_functions( + self, + **kwargs: Any + ) -> AsyncItemPaged[Dict[str, Any]]: """List all the user-defined functions in the container. - :param max_item_count: Max number of items to be returned in the enumeration operation. + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :returns: An AsyncItemPaged of user-defined functions (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count @@ -360,20 +382,26 @@ def list_user_defined_functions(self, max_item_count=None, **kwargs): ) @distributed_trace - def query_user_defined_functions(self, query, parameters=None, max_item_count=None, **kwargs): - # type: (str, Optional[List[str]], Optional[int], Any) -> AsyncItemPaged[Dict[str, Any]] + def query_user_defined_functions( + self, + query: Union[str, Dict[str, Any]], + **kwargs: Any + ) -> AsyncItemPaged[Dict[str, Any]]: """Return user-defined functions matching a given `query`. - :param query: The Azure Cosmos DB SQL query to execute. - :param parameters: Optional array of parameters to the query. Ignored if no query is provided. - :param max_item_count: Max number of items to be returned in the enumeration operation. + :param Union[str, Dict[str, Any]] query: The Azure Cosmos DB SQL query to execute. + :keyword parameters: Optional array of parameters to the query. Ignored if no query is provided. + :paramtype parameters: Optional[List[Dict[str, Any]]] + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :returns: An AsyncItemPaged of user-defined functions (dicts). :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = _build_options(kwargs) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count + parameters = kwargs.pop('parameters', None) return self.client_connection.QueryUserDefinedFunctions( collection_link=self.container_link, query=query if parameters is None else dict(query=query, parameters=parameters), @@ -382,14 +410,14 @@ def query_user_defined_functions(self, query, parameters=None, max_item_count=No ) @distributed_trace_async - async def get_user_defined_function(self, udf, **kwargs): - # type: (Union[str, Dict[str, Any]], Any) -> Dict[str, Any] + async def get_user_defined_function(self, udf: Union[str, Dict[str, Any]], **kwargs: Any) -> Dict[str, Any]: """Get a user-defined function identified by `id`. :param udf: The ID (name) or dict representing udf to retrieve. - :returns: A dict representing the retrieved user-defined function. + :type udf: Union[str, Dict[str, Any]] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the user-defined function couldn't be retrieved. - :rtype: dict[str, Any] + :returns: A dict representing the retrieved user-defined function. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) @@ -398,16 +426,16 @@ async def get_user_defined_function(self, udf, **kwargs): ) @distributed_trace_async - async def create_user_defined_function(self, body, **kwargs): - # type: (Dict[str, Any], Any) -> Dict[str, Any] + async def create_user_defined_function(self, body: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: """Create a user-defined function in the container. - To replace an existing UDF, use the :func:`ContainerProxy.scripts.replace_user_defined_function` method. + To replace an existing user-defined function, use the + :func:`ContainerProxy.scripts.replace_user_defined_function` method. - :param body: A dict-like object representing the udf to create. - :returns: A dict representing the new user-defined function. + :param Dict[str, Any] body: A dict-like object representing the user-defined function to create. :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the user-defined function couldn't be created. - :rtype: dict[str, Any] + :returns: A dict representing the new user-defined function. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) @@ -416,18 +444,23 @@ async def create_user_defined_function(self, body, **kwargs): ) @distributed_trace_async - async def replace_user_defined_function(self, udf, body, **kwargs): - # type: (Union[str, Dict[str, Any]], Dict[str, Any], Any) -> Dict[str, Any] + async def replace_user_defined_function( + self, + udf: Union[str, Dict[str, Any]], + body: Dict[str, Any], + **kwargs: Any + ) -> Dict[str, Any]: """Replace a specified user-defined function in the container. - If the UDF does not already exist in the container, an exception is raised. + If the user-defined function does not already exist in the container, an exception is raised. - :param udf: The ID (name) or dict representing udf to be replaced. - :param body: A dict-like object representing the udf to replace. - :returns: A dict representing the user-defined function after replace went through. + :param udf: The ID (name) or dict representing user-defined function to be replaced. + :type udf: Union[str, Dict[str, Any]] + :param Dict[str, Any] body: A dict-like object representing the udf to replace. :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the replace failed or the user-defined function with the given id does not exist. - :rtype: dict[str, Any] + :returns: A dict representing the user-defined function after replace went through. + :rtype: Dict[str, Any] """ request_options = _build_options(kwargs) @@ -439,13 +472,13 @@ async def replace_user_defined_function(self, udf, body, **kwargs): ) @distributed_trace_async - async def delete_user_defined_function(self, udf, **kwargs): - # type: (Union[str, Dict[str, Any]], Any) -> None + async def delete_user_defined_function(self, udf: Union[str, Dict[str, Any]], **kwargs: Any) -> None: """Delete a specified user-defined function from the container. - If the UDF does not already exist in the container, an exception is raised. + If the user-defined function does not already exist in the container, an exception is raised. :param udf: The ID (name) or dict representing udf to be deleted. + :type udf: Union[str, Dict[str, Any]] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The udf wasn't deleted successfully. :raises ~azure.cosmos.exceptions.CosmosResourceNotFoundError: The UDF does not exist in the container. :rtype: None diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/user.py b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_user.py similarity index 68% rename from sdk/cosmos/azure-cosmos/azure/cosmos/aio/user.py rename to sdk/cosmos/azure-cosmos/azure/cosmos/aio/_user.py index 1cdb30433659..58563f9e1b12 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/user.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/_user.py @@ -24,7 +24,7 @@ """Create, read, update and delete users in the Azure Cosmos DB SQL API service. """ -from typing import Any, List, Dict, Union, cast, Optional +from typing import Any, Dict, Union, cast from azure.core.async_paging import AsyncItemPaged from azure.core.tracing.decorator_async import distributed_trace_async @@ -32,7 +32,7 @@ from ._cosmos_client_connection_async import CosmosClientConnection from .._base import build_options -from ..permission import Permission as _permission +from ..permission import Permission class UserProxy(object): @@ -42,19 +42,22 @@ class UserProxy(object): :func:`DatabaseProxy.get_user_client` method. """ - def __init__(self, client_connection, id, database_link, properties=None): # pylint: disable=redefined-builtin - # type: (CosmosClientConnection, str, str, Dict[str, Any]) -> None + def __init__( + self, + client_connection: CosmosClientConnection, + id: str, # pylint: disable=redefined-builtin + database_link: str, + properties: Dict[str, Any] = None + ) -> None: self.client_connection = client_connection self.id = id self.user_link = u"{}/users/{}".format(database_link, id) self._properties = properties - def __repr__(self): - # type () -> str + def __repr__(self) -> str: return "".format(self.user_link)[:1024] - def _get_permission_link(self, permission_or_id): - # type: (Union[Permission, str, Dict[str, Any]]) -> str + def _get_permission_link(self, permission_or_id: Union[Permission, str, Dict[str, Any]]) -> str: if isinstance(permission_or_id, str): return u"{}/permissions/{}".format(self.user_link, permission_or_id) try: @@ -63,21 +66,20 @@ def _get_permission_link(self, permission_or_id): pass return u"{}/permissions/{}".format(self.user_link, cast("Dict[str, str]", permission_or_id)["id"]) - async def _get_properties(self): - # type: () -> Dict[str, Any] + async def _get_properties(self) -> Dict[str, Any]: if self._properties is None: self._properties = await self.read() return self._properties @distributed_trace_async - async def read(self, **kwargs): - # type: (Any) -> Dict[str, Any] - """Read user propertes. + async def read(self, **kwargs: Any) -> Dict[str, Any]: + """Read user properties. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A dictionary of the retrieved user properties. + :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 the given user couldn't be retrieved. - :rtype: dict[str, Any] + :returns: A dictionary of the retrieved user properties. + :rtype: Dict[str, Any] """ request_options = build_options(kwargs) response_hook = kwargs.pop('response_hook', None) @@ -91,17 +93,18 @@ async def read(self, **kwargs): return cast('Dict[str, Any]', self._properties) @distributed_trace - def list_permissions(self, max_item_count=None, **kwargs): - # type: (Optional[int], Any) -> AsyncItemPaged[Dict[str, Any]] + def list_permissions(self, **kwargs: Any) -> AsyncItemPaged[Dict[str, Any]]: """List all permission for the user. - :param max_item_count: Max number of permissions to be returned in the enumeration operation. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword int max_item_count: Max number of permissions to be returned in the enumeration operation. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]], None] :returns: An AsyncItemPaged of permissions (dicts). - :rtype: AsyncItemPaged[dict[str, Any]] + :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count @@ -115,26 +118,27 @@ def list_permissions(self, max_item_count=None, **kwargs): @distributed_trace def query_permissions( self, - query, - parameters=None, - max_item_count=None, - **kwargs - ): - # type: (str, Optional[List[str]], Optional[int], Any) -> AsyncItemPaged[Dict[str, Any]] + query: Union[str, Dict[str, Any]], + **kwargs: Any + ) -> AsyncItemPaged[Dict[str, Any]]: """Return all permissions matching the given `query`. - :param query: The Azure Cosmos DB SQL query to execute. - :param parameters: Optional array of parameters to the query. Ignored if no query is provided. - :param max_item_count: Max number of permissions to be returned in the enumeration operation. - :keyword Callable response_hook: A callable invoked with the response metadata. + :param Union[str, Dict[str, Any]] query: The Azure Cosmos DB SQL query to execute. + :keyword parameters: Optional array of parameters to the query. Ignored if no query is provided. + :paramtype parameters: Optional[List[Dict[str, Any]]] + :keyword int max_item_count: Max number of permissions to be returned in the enumeration operation. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], AsyncItemPaged[Dict[str, Any]]], None] :returns: An AsyncItemPaged of permissions (dicts). - :rtype: AsyncItemPaged[dict[str, Any]] + :rtype: AsyncItemPaged[Dict[str, Any]] """ feed_options = build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count + parameters = kwargs.pop('parameters', None) result = self.client_connection.QueryPermissions( user_link=self.user_link, query=query if parameters is None else dict(query=query, parameters=parameters), @@ -148,16 +152,21 @@ def query_permissions( return result @distributed_trace_async - async def get_permission(self, permission, **kwargs): - # type: (Union[str, Dict[str, Any], Permission], Any) -> Permission + async def get_permission( + self, + permission: Union[str, Dict[str, Any], Permission], + **kwargs: Any + ) -> Permission: """Get the permission identified by `id`. :param permission: The ID (name), dict representing the properties or :class:`Permission` instance of the permission to be retrieved. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A dict representing the retrieved permission. + :type permission: Union[str, Dict[str, Any], ~azure.cosmos.Permission] + :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 the given permission couldn't be retrieved. - :rtype: dict[str, Any] + :returns: The retrieved permission object. + :rtype: ~azure.cosmos.Permission """ request_options = build_options(kwargs) response_hook = kwargs.pop('response_hook', None) @@ -169,7 +178,7 @@ async def get_permission(self, permission, **kwargs): if response_hook: response_hook(self.client_connection.last_response_headers, permission_resp) - return _permission( + return Permission( id=permission_resp["id"], user_link=self.user_link, permission_mode=permission_resp["permissionMode"], @@ -178,17 +187,18 @@ async def get_permission(self, permission, **kwargs): ) @distributed_trace_async - async def create_permission(self, body, **kwargs): - # type: (Dict[str, Any], Any) -> Permission + async def create_permission(self, body: Dict[str, Any], **kwargs: Any) -> Permission: """Create a permission for the user. - To update or replace an existing permision, use the :func:`UserProxy.upsert_permission` method. + To update or replace an existing permission, use the :func:`UserProxy.upsert_permission` method. :param body: A dict-like object representing the permission to create. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A dict representing the new permission. + :type body: Dict[str, Any] + :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 the given permission couldn't be created. - :rtype: dict[str, Any] + :returns: A permission object representing the new permission. + :rtype: ~azure.cosmos.Permission """ request_options = build_options(kwargs) response_hook = kwargs.pop('response_hook', None) @@ -200,7 +210,7 @@ async def create_permission(self, body, **kwargs): if response_hook: response_hook(self.client_connection.last_response_headers, permission) - return _permission( + return Permission( id=permission["id"], user_link=self.user_link, permission_mode=permission["permissionMode"], @@ -209,18 +219,19 @@ async def create_permission(self, body, **kwargs): ) @distributed_trace_async - async def upsert_permission(self, body, **kwargs): - # type: (Dict[str, Any], Any) -> Permission + async def upsert_permission(self, body: Dict[str, Any], **kwargs: Any) -> Permission: """Insert or update the specified permission. If the permission already exists in the container, it is replaced. If the permission does not exist, it is inserted. :param body: A dict-like object representing the permission to update or insert. - :param Callable response_hook: A callable invoked with the response metadata. - :returns: A dict representing the upserted permission. + :type body: Dict[str, Any] + :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 the given permission could not be upserted. - :rtype: dict[str, Any] + :returns: A dict representing the upserted permission. + :rtype: ~azure.cosmos.Permission """ request_options = build_options(kwargs) response_hook = kwargs.pop('response_hook', None) @@ -232,7 +243,7 @@ async def upsert_permission(self, body, **kwargs): if response_hook: response_hook(self.client_connection.last_response_headers, permission) - return _permission( + return Permission( id=permission["id"], user_link=self.user_link, permission_mode=permission["permissionMode"], @@ -241,20 +252,27 @@ async def upsert_permission(self, body, **kwargs): ) @distributed_trace_async - async def replace_permission(self, permission, body, **kwargs): - # type: (str, Union[str, Dict[str, Any], Permission], Any) -> Permission + async def replace_permission( + self, + permission: Union[str, Dict[str, Any], Permission], + body: Dict[str, Any], + **kwargs: Any + ) -> Permission: """Replaces the specified permission if it exists for the user. If the permission does not already exist, an exception is raised. :param permission: The ID (name), dict representing the properties or :class:`Permission` instance of the permission to be replaced. + :type permission: Union[str, Dict[str, Any], ~azure.cosmos.Permission] :param body: A dict-like object representing the permission to replace. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A dict representing the permission after replace went through. + :type body: Dict[str, Any] + :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 the replace failed or the permission with given id does not exist. - :rtype: dict[str, Any] + :returns: A permission object representing the permission after the replace went through. + :rtype: ~azure.cosmos.Permission """ request_options = build_options(kwargs) response_hook = kwargs.pop('response_hook', None) @@ -266,7 +284,7 @@ async def replace_permission(self, permission, body, **kwargs): if response_hook: response_hook(self.client_connection.last_response_headers, permission_resp) - return _permission( + return Permission( id=permission_resp["id"], user_link=self.user_link, permission_mode=permission_resp["permissionMode"], @@ -275,15 +293,16 @@ async def replace_permission(self, permission, body, **kwargs): ) @distributed_trace_async - async def delete_permission(self, permission, **kwargs): - # type: (Union[str, Dict[str, Any], Permission], Any) -> None + async def delete_permission(self, permission: Union[str, Dict[str, Any], Permission], **kwargs: Any) -> None: """Delete the specified permission from the user. If the permission does not already exist, an exception is raised. :param permission: The ID (name), dict representing the properties or :class:`Permission` instance of the permission to be deleted. - :keyword Callable response_hook: A callable invoked with the response metadata. + :type permission: Union[str, Dict[str, Any], ~azure.cosmos.Permission] + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str], None], None] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The permission wasn't deleted successfully. :raises ~azure.cosmos.exceptions.CosmosResourceNotFoundError: The permission does not exist for the user. :rtype: None diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/cosmos_client.py b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/cosmos_client.py index 1ce24f2a2bf3..7fb3108e037e 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/aio/cosmos_client.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/aio/cosmos_client.py @@ -22,8 +22,9 @@ """Create, read, and delete databases in the Azure Cosmos DB SQL API service. """ -from typing import Any, Dict, Optional, Union, cast, List +from typing import Any, Dict, Optional, Union, cast from azure.core.async_paging import AsyncItemPaged +from azure.core.credentials import TokenCredential from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.tracing.decorator import distributed_trace @@ -32,28 +33,27 @@ from ._cosmos_client_connection_async import CosmosClientConnection from .._base import build_options as _build_options from ._retry_utility_async import _ConnectionRetryPolicy -from .database import DatabaseProxy +from ._database import DatabaseProxy from ..documents import ConnectionPolicy, DatabaseAccount from ..exceptions import CosmosResourceNotFoundError __all__ = ("CosmosClient",) -def _build_connection_policy(kwargs): - # type: (Dict[str, Any]) -> ConnectionPolicy +def _build_connection_policy(kwargs: Dict[str, Any]) -> ConnectionPolicy: # pylint: disable=protected-access policy = kwargs.pop('connection_policy', None) or ConnectionPolicy() # Connection config policy.RequestTimeout = kwargs.pop('request_timeout', None) or \ - kwargs.pop('connection_timeout', None) or \ - policy.RequestTimeout + kwargs.pop('connection_timeout', None) or \ + policy.RequestTimeout policy.ConnectionMode = kwargs.pop('connection_mode', None) or policy.ConnectionMode policy.ProxyConfiguration = kwargs.pop('proxy_config', None) or policy.ProxyConfiguration policy.EnableEndpointDiscovery = kwargs.pop('enable_endpoint_discovery', None) or policy.EnableEndpointDiscovery policy.PreferredLocations = kwargs.pop('preferred_locations', None) or policy.PreferredLocations policy.UseMultipleWriteLocations = kwargs.pop('multiple_write_locations', None) or \ - policy.UseMultipleWriteLocations + policy.UseMultipleWriteLocations # SSL config verify = kwargs.pop('connection_verify', None) @@ -96,8 +96,9 @@ class CosmosClient(object): # pylint: disable=client-accepts-api-version-keywor :param str url: The URL of the Cosmos DB account. :param credential: Can be the account key, or a dictionary of resource tokens. - :type credential: str or dict[str, str] - :param str consistency_level: Consistency level to use for the session. The default value is None (Account level). + :type credential: Union[str, Dict[str, str], ~azure.core.credentials_async.AsyncTokenCredential] + :keyword str consistency_level: Consistency level to use for the session. Default value is None (account-level). + More on consistency levels and possible values: https://aka.ms/cosmos-consistency-levels .. admonition:: Example: @@ -110,8 +111,14 @@ class CosmosClient(object): # pylint: disable=client-accepts-api-version-keywor :name: create_client """ - def __init__(self, url, credential, consistency_level=None, **kwargs): - # type: (str, Any, Optional[str], Any) -> None + def __init__( + self, + url: str, + credential: Union[str, Dict[str, str], TokenCredential], + *, + consistency_level: Optional[str] = None, + **kwargs: Any + ) -> None: """Instantiate a new CosmosClient.""" auth = _build_auth(credential) connection_policy = _build_connection_policy(kwargs) @@ -123,8 +130,7 @@ def __init__(self, url, credential, consistency_level=None, **kwargs): **kwargs ) - def __repr__(self): - # type: () -> str + def __repr__(self) -> str: return "".format(self.client_connection.url_connection)[:1024] async def __aenter__(self): @@ -135,40 +141,42 @@ async def __aenter__(self): async def __aexit__(self, *args): return await self.client_connection.pipeline_client.__aexit__(*args) - async def close(self): - # type: () -> None + async def close(self) -> None: """Close this instance of CosmosClient.""" await self.__aexit__() @classmethod - def from_connection_string(cls, conn_str, credential=None, consistency_level=None, **kwargs): - # type: (str, Optional[Union[str, Dict[str, str]]], Optional[str], Any) -> CosmosClient + def from_connection_string( + cls, + conn_str: str, + *, + credential: Optional[Union[str, Dict[str, str]]] = None, + consistency_level: Optional[str] = None, + **kwargs: Any + ) -> "CosmosClient": """Create a CosmosClient instance from a connection string. This can be retrieved from the Azure portal.For full list of optional keyword arguments, see the CosmosClient constructor. - :param conn_str: The connection string. - :type conn_str: str - :param credential: Alternative credentials to use instead of the key - provided in the connection string. - :type credential: str or Dict[str, str] - :param conn_str: The connection string. - :type conn_str: str - :param consistency_level: Consistency level to use for the session. The default value is None (Account level). - :type consistency_level: Optional[str] + :param str conn_str: The connection string. + :keyword credential: Alternative credentials to use instead of the key provided in the connection string. + :paramtype credential: Union[str, Dict[str, str]] + :keyword str consistency_level: Consistency level to use for the session. Default value is None (account-level). + More on consistency levels and possible values: https://aka.ms/cosmos-consistency-levels + :returns: a CosmosClient instance + :rtype: ~azure.cosmos.aio.CosmosClient """ settings = _parse_connection_str(conn_str, credential) return cls( url=settings['AccountEndpoint'], - credential=credential or settings['AccountKey'], + credential=settings['AccountKey'], consistency_level=consistency_level, **kwargs ) @staticmethod - def _get_database_link(database_or_id): - # type: (Union[DatabaseProxy, str, Dict[str, str]]) -> str + def _get_database_link(database_or_id: Union[DatabaseProxy, str, Dict[str, str]]) -> str: if isinstance(database_or_id, str): return "dbs/{}".format(database_or_id) try: @@ -180,26 +188,27 @@ def _get_database_link(database_or_id): @distributed_trace_async async def create_database( # pylint: disable=redefined-builtin - self, - id, # type: str - offer_throughput=None, # type: Optional[int] - **kwargs # type: Any - ): - # type: (...) -> DatabaseProxy + self, + id: str, + **kwargs: Any + ) -> DatabaseProxy: """ Create a new database with the given ID (name). :param id: ID (name) of the database to create. - :param int offer_throughput: The provisioned throughput for this offer. + :type id: str + :keyword int offer_throughput: The provisioned throughput for this offer. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword Callable response_hook: A callable invoked with the response metadata. - :returns: A DatabaseProxy instance representing the new database. - :rtype: ~azure.cosmos.DatabaseProxy + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :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.CosmosResourceExistsError: Database with the given ID already exists. + :returns: A DatabaseProxy instance representing the new database. + :rtype: ~azure.cosmos.aio.DatabaseProxy .. admonition:: Example: @@ -214,22 +223,21 @@ async def create_database( # pylint: disable=redefined-builtin request_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + offer_throughput = kwargs.pop('offer_throughput', None) if offer_throughput is not None: request_options["offerThroughput"] = offer_throughput result = await self.client_connection.CreateDatabase(database=dict(id=id), options=request_options, **kwargs) if response_hook: - response_hook(self.client_connection.last_response_headers) + response_hook(self.client_connection.last_response_headers, result) return DatabaseProxy(self.client_connection, id=result["id"], properties=result) @distributed_trace_async async def create_database_if_not_exists( # pylint: disable=redefined-builtin - self, - id, # type: str - offer_throughput=None, # type: Optional[int] - **kwargs # type: Any - ): - # type: (...) -> DatabaseProxy + self, + id: str, + **kwargs: Any + ) -> DatabaseProxy: """ Create the database if it does not exist already. @@ -239,17 +247,19 @@ async def create_database_if_not_exists( # pylint: disable=redefined-builtin This function does not check or update existing database settings or offer throughput if they differ from what is passed in. - :param id: ID (name) of the database to read or create. - :param int offer_throughput: The provisioned throughput for this offer. + :param str id: ID (name) of the database to read or create. + :keyword int offer_throughput: The provisioned throughput for this offer. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :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: The database read or creation failed. :returns: A DatabaseProxy instance representing the database. :rtype: ~azure.cosmos.DatabaseProxy - :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: The database read or creation failed. """ try: database_proxy = self.get_database_client(id) @@ -258,16 +268,15 @@ async def create_database_if_not_exists( # pylint: disable=redefined-builtin except CosmosResourceNotFoundError: return await self.create_database( id, - offer_throughput=offer_throughput, **kwargs ) - def get_database_client(self, database): - # type: (Union[str, DatabaseProxy, Dict[str, Any]]) -> DatabaseProxy + def get_database_client(self, database: Union[str, DatabaseProxy, Dict[str, Any]]) -> DatabaseProxy: """Retrieve an existing database with the ID (name) `id`. - :param database: The ID (name) representing the properties of the database to read. - :type database: str or dict(str, str) or ~azure.cosmos.DatabaseProxy + :param database: The ID (name), dict representing the properties, or :class:`DatabaseProxy` + instance of the database to get. + :type database: Union[str, ~azure.cosmos.DatabaseProxy, Dict[str, Any]] :returns: A `DatabaseProxy` instance representing the retrieved database. :rtype: ~azure.cosmos.DatabaseProxy """ @@ -283,22 +292,22 @@ def get_database_client(self, database): @distributed_trace def list_databases( - self, - max_item_count=None, # type: Optional[int] - **kwargs # type: Any - ): - # type: (...) -> AsyncItemPaged[Dict[str, Any]] + self, + **kwargs: Any + ) -> AsyncItemPaged[Dict[str, Any]]: """List the databases in a Cosmos DB SQL database account. - :param int max_item_count: Max number of items to be returned in the enumeration operation. + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str]], None] :returns: An AsyncItemPaged of database properties (dicts). - :rtype: AsyncItemPaged[dict[str, str]] + :rtype: AsyncItemPaged[Dict[str, str]] """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count @@ -309,31 +318,31 @@ def list_databases( @distributed_trace def query_databases( - self, - query, # type: str - parameters=None, # type: Optional[List[Dict[str, Any]]] - max_item_count=None, # type: Optional[int] - **kwargs # type: Any - ): - # type: (...) -> AsyncItemPaged[Dict[str, Any]] + self, + **kwargs: Any + ) -> AsyncItemPaged[Dict[str, Any]]: """Query the databases in a Cosmos DB SQL database account. - :param str query: The Azure Cosmos DB SQL query to execute. - :param list[dict[str, any]] parameters: Optional array of parameters to the query. + :keyword Union[str, Dict[str, Any]] query: The Azure Cosmos DB SQL query to execute. + :keyword parameters: Optional array of parameters to the query. Each parameter is a dict() with 'name' and 'value' keys. - Ignored if no query is provided. - :param int max_item_count: Max number of items to be returned in the enumeration operation. + :paramtype parameters: List[Dict[str, Any]] + :keyword int max_item_count: Max number of items to be returned in the enumeration operation. :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str]], None] :returns: An AsyncItemPaged of database properties (dicts). - :rtype: AsyncItemPaged[dict[str, str]] + :rtype: AsyncItemPaged[Dict[str, str]] """ feed_options = _build_options(kwargs) response_hook = kwargs.pop('response_hook', None) + max_item_count = kwargs.pop('max_item_count', None) if max_item_count is not None: feed_options["maxItemCount"] = max_item_count + parameters = kwargs.pop('parameters', None) + query = kwargs.pop('query', None) result = self.client_connection.QueryDatabases( query=query if parameters is None else dict(query=query, parameters=parameters), options=feed_options, @@ -344,22 +353,23 @@ def query_databases( @distributed_trace_async async def delete_database( - self, - database, # type: Union[str, DatabaseProxy, Dict[str, Any]] - **kwargs # type: Any - ): - # type: (...) -> None + self, + database: Union[str, DatabaseProxy, Dict[str, Any]], + **kwargs: Any + ) -> None: """Delete the database with the given ID (name). :param database: The ID (name), dict representing the properties, or :class:`DatabaseProxy` instance of the database to delete. - :type database: str or dict(str, str) or ~azure.cosmos.DatabaseProxy + :type database: Union[str, ~azure.cosmos.DatabaseProxy, Dict[str, Any]] :keyword str session_token: Token for use with Session consistency. - :keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request. + :keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request. :keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource has changed, and act according to the condition specified by the `match_condition` parameter. - :keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword match_condition: The match condition to use upon the etag. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str]], None] :raises ~azure.cosmos.exceptions.CosmosHttpResponseError: If the database couldn't be deleted. :rtype: None """ @@ -372,11 +382,11 @@ async def delete_database( response_hook(self.client_connection.last_response_headers) @distributed_trace_async - async def _get_database_account(self, **kwargs): - # type: (Any) -> DatabaseAccount + async def _get_database_account(self, **kwargs: Any) -> DatabaseAccount: """Retrieve the database account information. - :keyword Callable response_hook: A callable invoked with the response metadata. + :keyword response_hook: A callable invoked with the response metadata. + :paramtype response_hook: Callable[[Dict[str, str]], None] :returns: A `DatabaseAccount` instance representing the Cosmos DB Database Account. :rtype: ~azure.cosmos.DatabaseAccount """ diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/container.py b/sdk/cosmos/azure-cosmos/azure/cosmos/container.py index 9f075eba64d5..b23a3c992546 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/container.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/container.py @@ -340,7 +340,7 @@ def query_items( For accounts configured to use the integrated cache, using Session or Eventual consistency, responses are guaranteed to be no staler than this value. :returns: An Iterable of items (dicts). - :rtype: Iterable[dict[str, Any]] + :rtype: ItemPaged[Dict[str, Any]] .. admonition:: Example: diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/cosmos_client.py b/sdk/cosmos/azure-cosmos/azure/cosmos/cosmos_client.py index 3592f9d5a935..ab10405214f4 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/cosmos_client.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/cosmos_client.py @@ -136,7 +136,7 @@ class CosmosClient(object): # pylint: disable=client-accepts-api-version-keywor :param str url: The URL of the Cosmos DB account. :param credential: Can be the account key, or a dictionary of resource tokens. - :type credential: str or dict[str, str] + :type credential: Union[str, Dict[str, str], ~azure.core.credentials.TokenCredential] :param str consistency_level: Consistency level to use for the session. The default value is None (Account level). :keyword int timeout: An absolute timeout in seconds, for the combined HTTP request and response processing. :keyword int request_timeout: The HTTP request timeout in milliseconds. diff --git a/sdk/cosmos/azure-cosmos/setup.py b/sdk/cosmos/azure-cosmos/setup.py index f206cdb487a8..2ce020e9c43e 100644 --- a/sdk/cosmos/azure-cosmos/setup.py +++ b/sdk/cosmos/azure-cosmos/setup.py @@ -71,6 +71,6 @@ packages=find_packages(exclude=exclude_packages), python_requires=">=3.6", install_requires=[ - 'azure-core<2.0.0,>=1.2.2' + 'azure-core<2.0.0,>=1.23.0' ], ) diff --git a/shared_requirements.txt b/shared_requirements.txt index 4a33c8965dff..1f7d15bda4b9 100644 --- a/shared_requirements.txt +++ b/shared_requirements.txt @@ -136,7 +136,7 @@ chardet<5,>=3.0.2 #override azure-containerregistry azure-core>=1.23.0,<2.0.0 #override azure-core-tracing-opencensus azure-core<2.0.0,>=1.13.0 #override azure-core-tracing-opentelemetry azure-core<2.0.0,>=1.13.0 -#override azure-cosmos azure-core<2.0.0,>=1.0.0 +#override azure-cosmos azure-core<2.0.0,>=1.23.0 #override azure-data-tables azure-core<2.0.0,>=1.15.0 #override azure-data-tables msrest>=0.6.10 #override azure-eventhub azure-core<2.0.0,>=1.14.0