From 65d8dc4625ae2f7d7b5d09cb92e94a854d636b09 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 17:37:55 +0000 Subject: [PATCH 1/4] Initial plan From 4f6ede0ceb7a0a1c3763c237abfa2f8ec4d00c3f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 17:50:58 +0000 Subject: [PATCH 2/4] Fix on_duplicate and on_missing to be passed through methods not stored on body Co-authored-by: SoulPancake <70265851+SoulPancake@users.noreply.github.com> --- openfga_sdk/client/client.py | 16 ++++---- openfga_sdk/client/models/write_request.py | 46 ++++------------------ openfga_sdk/sync/client/client.py | 16 ++++---- 3 files changed, 26 insertions(+), 52 deletions(-) diff --git a/openfga_sdk/client/client.py b/openfga_sdk/client/client.py index d447264..aa3a5e3 100644 --- a/openfga_sdk/client/client.py +++ b/openfga_sdk/client/client.py @@ -543,19 +543,21 @@ async def _write_with_transaction( kwargs = options_to_kwargs(options) conflict_options = options_to_conflict_info(options) - # Set conflict options on the body if provided + # Extract conflict options to pass to the tuple key methods + on_duplicate = None + on_missing = None if conflict_options: if conflict_options.on_duplicate_writes: - body.on_duplicate = conflict_options.on_duplicate_writes.value + on_duplicate = conflict_options.on_duplicate_writes.value if conflict_options.on_missing_deletes: - body.on_missing = conflict_options.on_missing_deletes.value + on_missing = conflict_options.on_missing_deletes.value writes_tuple_keys = None deletes_tuple_keys = None - if body.writes_tuple_keys: - writes_tuple_keys = body.writes_tuple_keys - if body.deletes_tuple_keys: - deletes_tuple_keys = body.deletes_tuple_keys + if body.writes: + writes_tuple_keys = body.writes_tuple_keys(on_duplicate=on_duplicate) + if body.deletes: + deletes_tuple_keys = body.deletes_tuple_keys(on_missing=on_missing) await self._api.write( WriteRequest( diff --git a/openfga_sdk/client/models/write_request.py b/openfga_sdk/client/models/write_request.py index 49b6154..5117831 100644 --- a/openfga_sdk/client/models/write_request.py +++ b/openfga_sdk/client/models/write_request.py @@ -24,13 +24,9 @@ def __init__( self, writes: list[ClientTuple] | None = None, deletes: list[ClientTuple] | None = None, - on_duplicate: str | None = None, - on_missing: str | None = None, ) -> None: self._writes = writes self._deletes = deletes - self._on_duplicate = on_duplicate - self._on_missing = on_missing @property def writes(self) -> list[ClientTuple] | None: @@ -60,36 +56,9 @@ def deletes(self, value: list[ClientTuple] | None) -> None: """ self._deletes = value - @property - def on_duplicate(self) -> str | None: - """ - Return on_duplicate - """ - return self._on_duplicate - - @on_duplicate.setter - def on_duplicate(self, value: str | None) -> None: - """ - Set on_duplicate - """ - self._on_duplicate = value - - @property - def on_missing(self) -> str | None: - """ - Return on_missing - """ - return self._on_missing - - @on_missing.setter - def on_missing(self, value: str | None) -> None: - """ - Set on_missing - """ - self._on_missing = value - - @property - def writes_tuple_keys(self) -> WriteRequestWrites | None: + def writes_tuple_keys( + self, on_duplicate: str | None = None + ) -> WriteRequestWrites | None: """ Return the writes as tuple keys """ @@ -101,10 +70,11 @@ def writes_tuple_keys(self) -> WriteRequestWrites | None: if keys is None: return None - return WriteRequestWrites(tuple_keys=keys, on_duplicate=self._on_duplicate) + return WriteRequestWrites(tuple_keys=keys, on_duplicate=on_duplicate) - @property - def deletes_tuple_keys(self) -> WriteRequestDeletes | None: + def deletes_tuple_keys( + self, on_missing: str | None = None + ) -> WriteRequestDeletes | None: """ Return the delete as tuple keys """ @@ -116,4 +86,4 @@ def deletes_tuple_keys(self) -> WriteRequestDeletes | None: if keys is None: return None - return WriteRequestDeletes(tuple_keys=keys, on_missing=self._on_missing) + return WriteRequestDeletes(tuple_keys=keys, on_missing=on_missing) diff --git a/openfga_sdk/sync/client/client.py b/openfga_sdk/sync/client/client.py index 1aa2d87..edc5723 100644 --- a/openfga_sdk/sync/client/client.py +++ b/openfga_sdk/sync/client/client.py @@ -543,19 +543,21 @@ def _write_with_transaction( kwargs = options_to_kwargs(options) conflict_options = options_to_conflict_info(options) - # Set conflict options on the body if provided + # Extract conflict options to pass to the tuple key methods + on_duplicate = None + on_missing = None if conflict_options: if conflict_options.on_duplicate_writes: - body.on_duplicate = conflict_options.on_duplicate_writes.value + on_duplicate = conflict_options.on_duplicate_writes.value if conflict_options.on_missing_deletes: - body.on_missing = conflict_options.on_missing_deletes.value + on_missing = conflict_options.on_missing_deletes.value writes_tuple_keys = None deletes_tuple_keys = None - if body.writes_tuple_keys: - writes_tuple_keys = body.writes_tuple_keys - if body.deletes_tuple_keys: - deletes_tuple_keys = body.deletes_tuple_keys + if body.writes: + writes_tuple_keys = body.writes_tuple_keys(on_duplicate=on_duplicate) + if body.deletes: + deletes_tuple_keys = body.deletes_tuple_keys(on_missing=on_missing) self._api.write( WriteRequest( From a9d1514ecbdff7b7179d7a46e49e4075c07b36b4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 17:54:53 +0000 Subject: [PATCH 3/4] Fix default behavior for on_duplicate and on_missing Co-authored-by: SoulPancake <70265851+SoulPancake@users.noreply.github.com> --- openfga_sdk/client/models/write_request.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openfga_sdk/client/models/write_request.py b/openfga_sdk/client/models/write_request.py index 5117831..b07c3f4 100644 --- a/openfga_sdk/client/models/write_request.py +++ b/openfga_sdk/client/models/write_request.py @@ -70,7 +70,9 @@ def writes_tuple_keys( if keys is None: return None - return WriteRequestWrites(tuple_keys=keys, on_duplicate=on_duplicate) + if on_duplicate is not None: + return WriteRequestWrites(tuple_keys=keys, on_duplicate=on_duplicate) + return WriteRequestWrites(tuple_keys=keys) def deletes_tuple_keys( self, on_missing: str | None = None @@ -86,4 +88,6 @@ def deletes_tuple_keys( if keys is None: return None - return WriteRequestDeletes(tuple_keys=keys, on_missing=on_missing) + if on_missing is not None: + return WriteRequestDeletes(tuple_keys=keys, on_missing=on_missing) + return WriteRequestDeletes(tuple_keys=keys) From 3b841edb569dece37a70cb0df2288857e4412848 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 18:40:24 +0000 Subject: [PATCH 4/4] Fix all test expectations to include default on_duplicate and on_missing values Co-authored-by: SoulPancake <70265851+SoulPancake@users.noreply.github.com> --- test/client/client_test.py | 59 +++++++++++++++++++++++---------- test/sync/client/client_test.py | 53 +++++++++++++++++++---------- 2 files changed, 78 insertions(+), 34 deletions(-) diff --git a/test/client/client_test.py b/test/client/client_test.py index 2949d84..be8fff4 100644 --- a/test/client/client_test.py +++ b/test/client/client_test.py @@ -1026,7 +1026,8 @@ async def test_write(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", }, - ] + ], + "on_duplicate": "error", }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1071,7 +1072,10 @@ async def test_delete(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", } - ] + ], + "on_missing": "error", + "on_missing": "error", + "on_missing": "error", }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1171,7 +1175,8 @@ async def test_write_batch(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1192,7 +1197,8 @@ async def test_write_batch(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31c", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1213,7 +1219,8 @@ async def test_write_batch(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1313,7 +1320,8 @@ async def test_write_batch_min_parallel(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1334,7 +1342,8 @@ async def test_write_batch_min_parallel(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31c", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1355,7 +1364,8 @@ async def test_write_batch_min_parallel(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1459,7 +1469,8 @@ async def test_write_batch_larger_chunk(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31c", }, - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1480,7 +1491,8 @@ async def test_write_batch_larger_chunk(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1594,7 +1606,8 @@ async def test_write_batch_failed(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1615,7 +1628,8 @@ async def test_write_batch_failed(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31c", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1636,7 +1650,8 @@ async def test_write_batch_failed(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1690,7 +1705,9 @@ async def test_delete_batch(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", } - ] + ], + "on_missing": "error", + "on_missing": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1753,7 +1770,8 @@ async def test_write_tuples(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", }, - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1816,7 +1834,9 @@ async def test_delete_tuples(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", }, - ] + ], + "on_missing": "error", + "on_missing": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1872,7 +1892,8 @@ async def test_write_batch_unauthorized(self, mock_request): "relation": "reader", "object": "document:2021-budget", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -4076,6 +4097,8 @@ async def test_write_with_conflict_options_ignore_missing_deletes( "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", }, ], + "on_missing": "error", + "on_missing": "error", "on_missing": "ignore", }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", @@ -4153,6 +4176,8 @@ async def test_write_with_conflict_options_both(self, mock_request): "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31c", }, ], + "on_missing": "error", + "on_missing": "error", "on_missing": "ignore", }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", diff --git a/test/sync/client/client_test.py b/test/sync/client/client_test.py index dc8b033..ac8d34c 100644 --- a/test/sync/client/client_test.py +++ b/test/sync/client/client_test.py @@ -1024,7 +1024,8 @@ def test_write(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", }, - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1069,7 +1070,8 @@ def test_delete(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", } - ] + ], + "on_missing": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1169,7 +1171,8 @@ def test_write_batch(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1190,7 +1193,8 @@ def test_write_batch(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31c", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1211,7 +1215,8 @@ def test_write_batch(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1311,7 +1316,8 @@ def test_write_batch_min_parallel(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1332,7 +1338,8 @@ def test_write_batch_min_parallel(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31c", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1353,7 +1360,8 @@ def test_write_batch_min_parallel(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1458,7 +1466,8 @@ def test_write_batch_larger_chunk(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31c", }, - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1479,7 +1488,8 @@ def test_write_batch_larger_chunk(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1593,7 +1603,8 @@ def test_write_batch_failed(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1614,7 +1625,8 @@ def test_write_batch_failed(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31c", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1635,7 +1647,8 @@ def test_write_batch_failed(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1689,7 +1702,8 @@ def test_delete_batch(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", } - ] + ], + "on_missing": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1752,7 +1766,8 @@ def test_write_tuples(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", }, - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1815,7 +1830,8 @@ def test_delete_tuples(self, mock_request): "relation": "reader", "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31d", }, - ] + ], + "on_missing": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -1871,7 +1887,8 @@ def test_write_batch_unauthorized(self, mock_request): "relation": "reader", "object": "document:2021-budget", } - ] + ], + "on_duplicate": "error" }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", }, @@ -4059,6 +4076,7 @@ def test_sync_write_with_conflict_options_ignore_missing_deletes( "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31b", }, ], + "on_missing": "error", "on_missing": "ignore", }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J", @@ -4134,6 +4152,7 @@ def test_sync_write_with_conflict_options_both(self, mock_request): "user": "user:81684243-9356-4421-8fbf-a4f8d36aa31c", }, ], + "on_missing": "error", "on_missing": "ignore", }, "authorization_model_id": "01G5JAVJ41T49E9TT3SKVS7X1J",