diff --git a/README.md b/README.md index f05e33a..77a2868 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,3 @@ Use optimistic locking to put DynamoDB records with auto-incrementing attributes - https://aws.amazon.com/blogs/aws/new-amazon-dynamodb-transactions/ - https://bitesizedserverless.com/bite/reliable-auto-increments-in-dynamodb/ - -## FIXME - -This package currently depends on code that is in a pull request for boto3 that is not yet merged or released. -See https://github.com/boto/boto3/pull/4010. diff --git a/dynamodb_autoincrement.py b/dynamodb_autoincrement.py index 252c89c..d514ed4 100644 --- a/dynamodb_autoincrement.py +++ b/dynamodb_autoincrement.py @@ -9,6 +9,9 @@ from mypy_boto3_dynamodb.service_resource import DynamoDBServiceResource +# FIXME: remove instances of 'type: ignore[attr-defined]' below once +# boto3-missing becomes unnecessary. + PrimitiveDynamoDBValues = Optional[Union[str, int, float, Decimal, bool]] DynamoDBValues = Union[ @@ -33,18 +36,6 @@ class BaseDynamoDBAutoIncrement(ABC): def next(self, item: DynamoDBItem) -> tuple[Iterable[dict[str, Any]], str]: raise NotImplementedError - def _put_item(self, *, TableName, **kwargs): - # FIXME: DynamoDB resource does not have put_item method; emulate it - self.dynamodb.Table(TableName).put_item(**kwargs) - - def _get_item(self, *, TableName, **kwargs): - # FIXME: DynamoDB resource does not have get_item method; emulate it - return self.dynamodb.Table(TableName).get_item(**kwargs) - - def _query(self, *, TableName, **kwargs): - # FIXME: DynamoDB resource does not have put_item method; emulate it - return self.dynamodb.Table(TableName).query(**kwargs) - def put(self, item: DynamoDBItem): TransactionCanceledException = ( self.dynamodb.meta.client.exceptions.TransactionCanceledException @@ -53,11 +44,9 @@ def put(self, item: DynamoDBItem): puts, next_counter = self.next(item) if self.dangerously: for put in puts: - self._put_item(**put) + self.dynamodb.put_item(**put) # type: ignore[attr-defined] else: try: - # FIXME: depends on an unmerged PR for boto3. - # See https://github.com/boto/boto3/pull/4010 self.dynamodb.transact_write_items( # type: ignore[attr-defined] TransactItems=[{"Put": put} for put in puts] ) @@ -69,7 +58,7 @@ def put(self, item: DynamoDBItem): class DynamoDBAutoIncrement(BaseDynamoDBAutoIncrement): def next(self, item): counter = ( - self._get_item( + self.dynamodb.get_item( AttributesToGet=[self.attribute_name], Key=self.counter_table_key, TableName=self.counter_table_name, @@ -117,7 +106,7 @@ def next(self, item): class DynamoDBHistoryAutoIncrement(BaseDynamoDBAutoIncrement): def list(self) -> list[int]: - result = self._query( + result = self.dynamodb.query( # type: ignore[attr-defined] TableName=self.table_name, ExpressionAttributeNames={ **{f"#{i}": key for i, key in enumerate(self.counter_table_key.keys())}, @@ -145,10 +134,10 @@ def get(self, version: Optional[int] = None) -> DynamoDBItem: "TableName": self.table_name, "Key": {**self.counter_table_key, self.attribute_name: version}, } - return self._get_item(**kwargs).get("Item") + return self.dynamodb.get_item(**kwargs).get("Item") # type: ignore[attr-defined] def next(self, item): - existing_item = self._get_item( + existing_item = self.dynamodb.get_item( TableName=self.counter_table_name, Key=self.counter_table_key, ).get("Item") diff --git a/pyproject.toml b/pyproject.toml index bdd637e..176f4ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,8 @@ classifiers = [ "Topic :: Database", ] dependencies = [ - "boto3 @ git+https://github.com/lpsinger/boto3@dynamodb-resource-transact-write-items", + "boto3", + "boto3-missing", "boto3-stubs[dynamodb]", ] requires-python = ">=3.9" diff --git a/test_dynamodb_autoincrement.py b/test_dynamodb_autoincrement.py index f773e46..04155fc 100644 --- a/test_dynamodb_autoincrement.py +++ b/test_dynamodb_autoincrement.py @@ -91,19 +91,20 @@ def test_autoincrement_safely(autoincrement_safely, dynamodb, last_id): if last_id is None: next_id = 1 else: - dynamodb.Table("autoincrement").put_item( - Item={"tableName": "widgets", "widgetID": last_id} + dynamodb.put_item( + TableName="autoincrement", + Item={"tableName": "widgets", "widgetID": last_id}, ) next_id = last_id + 1 result = autoincrement_safely.put({"widgetName": "runcible spoon"}) assert result == next_id - assert dynamodb.Table("widgets").scan()["Items"] == [ + assert dynamodb.scan(TableName="widgets")["Items"] == [ {"widgetID": next_id, "widgetName": "runcible spoon"}, ] - assert dynamodb.Table("autoincrement").scan()["Items"] == [ + assert dynamodb.scan(TableName="autoincrement")["Items"] == [ { "tableName": "widgets", "widgetID": next_id, @@ -152,7 +153,7 @@ def test_autoincrement_dangerously_fails_on_many_parallel_puts( @pytest.fixture(params=[None, {"widgetID": 1}, {"widgetID": 1, "version": 1}]) def initial_item(request, create_tables, dynamodb): if request.param is not None: - dynamodb.Table("widgets").put_item(Item=request.param) + dynamodb.put_item(TableName="widgets", Item=request.param) return request.param @@ -174,7 +175,7 @@ def test_autoincrement_version( ) assert new_version == 1 + has_initial_item - history_items = dynamodb.Table("widgetHistory").query( + history_items = dynamodb.query( TableName="widgetHistory", KeyConditionExpression="widgetID = :widgetID", ExpressionAttributeValues={