Skip to content

Commit 2249e3c

Browse files
authored
[Cosmos] Etag handling bugfix and documentation rollback (#40282)
* revert documentation slip and fix etag behavior * test updates * Revert "test updates" This reverts commit ce4dbad. * dual None edge case that was being hit * Update CHANGELOG.md
1 parent f523b34 commit 2249e3c

File tree

6 files changed

+31
-26
lines changed

6 files changed

+31
-26
lines changed

sdk/cosmos/azure-cosmos/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#### Breaking Changes
88

99
#### Bugs Fixed
10+
* Fixed bug introduced in 4.10.0b3 with explicitly setting `etag` keyword argument as `None` causing exceptions. See [PR 40282](https://github.com/Azure/azure-sdk-for-python/pull/40282).
1011

1112
#### Other Changes
1213

sdk/cosmos/azure-cosmos/azure/cosmos/_base.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ def _get_match_headers(kwargs: Dict[str, Any]) -> Tuple[Optional[str], Optional[
8989
elif match_condition == MatchConditions.IfMissing:
9090
if_none_match = '*'
9191
elif match_condition is None:
92-
if 'etag' in kwargs:
92+
etag = kwargs.pop('etag', None)
93+
if etag is not None:
9394
raise ValueError("'etag' specified without 'match_condition'.")
9495
else:
9596
raise TypeError("Invalid match condition: {}".format(match_condition))

sdk/cosmos/azure-cosmos/azure/cosmos/aio/_container.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,8 @@ async def upsert_item(
726726
post_trigger_include: Optional[str] = None,
727727
session_token: Optional[str] = None,
728728
initial_headers: Optional[Dict[str, str]] = None,
729+
etag: Optional[str] = None,
730+
match_condition: Optional[MatchConditions] = None,
729731
priority: Optional[Literal["High", "Low"]] = None,
730732
no_response: Optional[bool] = None,
731733
**kwargs: Any
@@ -740,6 +742,10 @@ async def upsert_item(
740742
:keyword str post_trigger_include: trigger id to be used as post operation trigger.
741743
:keyword str session_token: Token for use with Session consistency.
742744
:keyword dict[str, str] initial_headers: Initial headers to be sent as part of the request.
745+
:keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource
746+
has changed, and act according to the condition specified by the `match_condition` parameter.
747+
:keyword match_condition: The match condition to use upon the etag.
748+
:paramtype match_condition: ~azure.core.MatchConditions
743749
:keyword response_hook: A callable invoked with the response metadata.
744750
:paramtype response_hook: Callable[[Mapping[str, str], Dict[str, Any]], None]
745751
:keyword Literal["High", "Low"] priority: Priority based execution allows users to set a priority for each
@@ -753,19 +759,6 @@ async def upsert_item(
753759
`no_response` is specified.
754760
:rtype: ~azure.cosmos.CosmosDict[str, Any]
755761
"""
756-
etag = kwargs.get('etag')
757-
if etag is not None:
758-
warnings.warn(
759-
"The 'etag' flag does not apply to this method and is always ignored even if passed."
760-
" It will now be removed in the future.",
761-
DeprecationWarning)
762-
match_condition = kwargs.get('match_condition')
763-
if match_condition is not None:
764-
warnings.warn(
765-
"The 'match_condition' flag does not apply to this method and is always ignored even if passed."
766-
" It will now be removed in the future.",
767-
DeprecationWarning)
768-
769762
if pre_trigger_include is not None:
770763
kwargs['pre_trigger_include'] = pre_trigger_include
771764
if post_trigger_include is not None:
@@ -776,6 +769,10 @@ async def upsert_item(
776769
kwargs['initial_headers'] = initial_headers
777770
if priority is not None:
778771
kwargs['priority'] = priority
772+
if etag is not None:
773+
kwargs['etag'] = etag
774+
if match_condition is not None:
775+
kwargs['match_condition'] = match_condition
779776
if no_response is not None:
780777
kwargs['no_response'] = no_response
781778
request_options = _build_options(kwargs)

sdk/cosmos/azure-cosmos/azure/cosmos/container.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,8 @@ def upsert_item( # pylint:disable=docstring-missing-param
766766
*,
767767
session_token: Optional[str] = None,
768768
initial_headers: Optional[Dict[str, str]] = None,
769+
etag: Optional[str] = None,
770+
match_condition: Optional[MatchConditions] = None,
769771
priority: Optional[Literal["High", "Low"]] = None,
770772
no_response: Optional[bool] = None,
771773
response_hook: Optional[Callable[[Mapping[str, str], Dict[str, Any]], None]] = None,
@@ -782,6 +784,9 @@ def upsert_item( # pylint:disable=docstring-missing-param
782784
:param str post_trigger_include: trigger id to be used as post operation trigger.
783785
:keyword str session_token: Token for use with Session consistency.
784786
:keyword Dict[str, str] initial_headers: Initial headers to be sent as part of the request.
787+
:keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource
788+
has changed, and act according to the condition specified by the `match_condition` parameter.
789+
:keyword ~azure.core.MatchConditions match_condition: The match condition to use upon the etag.
785790
:keyword response_hook: A callable invoked with the response metadata.
786791
:paramtype response_hook: Callable[[Mapping[str, str], Dict[str, Any]], None]
787792
:keyword Literal["High", "Low"] priority: Priority based execution allows users to set a priority for each
@@ -794,18 +799,6 @@ def upsert_item( # pylint:disable=docstring-missing-param
794799
:returns: A CosmosDict representing the upserted item. The dict will be empty if `no_response` is specified.
795800
:rtype: ~azure.cosmos.CosmosDict[str, Any]
796801
"""
797-
etag = kwargs.get('etag')
798-
if etag is not None:
799-
warnings.warn(
800-
"The 'etag' flag does not apply to this method and is always ignored even if passed."
801-
" It will now be removed in the future.",
802-
DeprecationWarning)
803-
match_condition = kwargs.get('match_condition')
804-
if match_condition is not None:
805-
warnings.warn(
806-
"The 'match_condition' flag does not apply to this method and is always ignored even if passed."
807-
" It will now be removed in the future.",
808-
DeprecationWarning)
809802
if pre_trigger_include is not None:
810803
kwargs['pre_trigger_include'] = pre_trigger_include
811804
if post_trigger_include is not None:
@@ -816,6 +809,10 @@ def upsert_item( # pylint:disable=docstring-missing-param
816809
kwargs['initial_headers'] = initial_headers
817810
if priority is not None:
818811
kwargs['priority'] = priority
812+
if etag is not None:
813+
kwargs['etag'] = etag
814+
if match_condition is not None:
815+
kwargs['match_condition'] = match_condition
819816
if no_response is not None:
820817
kwargs['no_response'] = no_response
821818
if response_hook is not None:

sdk/cosmos/azure-cosmos/tests/test_backwards_compatibility.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ def test_etag_match_condition_compatibility(self):
144144
item2 = container.upsert_item({"id": str(uuid.uuid4()), "pk": 0}, etag=str(uuid.uuid4()),
145145
match_condition=MatchConditions.IfNotModified)
146146
assert item2 is not None
147+
item = container.create_item({"id": str(uuid.uuid4()), "pk": 0}, etag=None, match_condition=None)
148+
assert item is not None
149+
item2 = container.upsert_item({"id": str(uuid.uuid4()), "pk": 0}, etag=None, match_condition=None)
150+
assert item2 is not None
147151
batch_operations = [
148152
("create", ({"id": str(uuid.uuid4()), "pk": 0},)),
149153
("replace", (item2['id'], {"id": str(uuid.uuid4()), "pk": 0})),

sdk/cosmos/azure-cosmos/tests/test_backwards_compatibility_async.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ async def test_etag_match_condition_compatibility_async(self):
127127
item2 = await container.upsert_item({"id": str(uuid.uuid4()), "pk": 0}, etag=str(uuid.uuid4()),
128128
match_condition=MatchConditions.IfNotModified)
129129
assert item2 is not None
130+
item = await container.create_item({"id": str(uuid.uuid4()), "pk": 0}, etag=None, match_condition=None)
131+
assert item is not None
132+
item2 = await container.upsert_item({"id": str(uuid.uuid4()), "pk": 0}, etag=None,
133+
match_condition=None)
134+
assert item2 is not None
130135
batch_operations = [
131136
("create", ({"id": str(uuid.uuid4()), "pk": 0},)),
132137
("replace", (item2['id'], {"id": str(uuid.uuid4()), "pk": 0})),

0 commit comments

Comments
 (0)