Skip to content

Commit

Permalink
add IntegerSetAttribute (#52)
Browse files Browse the repository at this point in the history
adding an IntegerSetAttribute
  • Loading branch information
knap1930 authored Mar 12, 2024
1 parent fe416dd commit 1a74dea
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ repos:
- id: debug-statements
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://gitlab.com/pycqa/flake8
- repo: https://github.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ This Python 3 library contains compound and high-level PynamoDB attributes:

- `FloatAttribute` – same as `NumberAttribute` but whose value is typed as `float`
- `IntegerAttribute` – same as `NumberAttribute` but whose value is typed as `int` (rather than `float`)
- `IntegerSetAttribute` – same as `NumberSetAttribute` but whose value is typed as `int` (rather than `float`)
- `UnicodeDelimitedTupleAttribute` - a delimiter-separated value, useful for storing composite keys
- `UnicodeEnumAttribute` - serializes a string-valued `Enum` into a Unicode (`S`-typed) attribute
- `UnicodeProtobufEnumAttribute` - serializes a Protobuf enum into a Unicode (`S`-typed) attribute
Expand Down
2 changes: 2 additions & 0 deletions pynamodb_attributes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .integer import IntegerAttribute
from .integer_date import IntegerDateAttribute
from .integer_enum import IntegerEnumAttribute
from .integer_set import IntegerSetAttribute
from .timedelta import TimedeltaAttribute
from .timedelta import TimedeltaMsAttribute
from .timedelta import TimedeltaUsAttribute
Expand All @@ -16,6 +17,7 @@
__all__ = [
"FloatAttribute",
"IntegerAttribute",
"IntegerSetAttribute",
"IntegerDateAttribute",
"IntegerEnumAttribute",
"UnicodeDelimitedTupleAttribute",
Expand Down
15 changes: 15 additions & 0 deletions pynamodb_attributes/integer_set.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Set

from pynamodb.attributes import Attribute
from pynamodb.attributes import NumberSetAttribute


class IntegerSetAttribute(Attribute[Set[int]]):
"""
Unlike NumberSetAttribute, this attribute has its type hinted as 'Set[int]'.
"""

attr_type = NumberSetAttribute.attr_type
null = NumberSetAttribute.null
serialize = NumberSetAttribute.serialize # type: ignore
deserialize = NumberSetAttribute.deserialize # type: ignore
6 changes: 3 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ universal = 1
[metadata]
license_file = LICENSE
name = pynamodb-attributes
version = 0.4.0
version = 0.5.0
description = Common attributes for PynamoDB
long_description = file:README.md
long_description_content_type = text/markdown
Expand Down Expand Up @@ -35,8 +35,8 @@ ignore = E203
addopts = --cov=pynamodb_attributes --cov-report=term-missing:skip-covered --cov-report=xml --cov-report=html -vvv
env =
# We don't need real AWS access in unit tests
D:AWS_ACCESS_KEY_ID=mock_aws_access_key_id
D:AWS_SECRET_ACCESS_KEY=mock_aws_secret_access_key
D:AWS_ACCESS_KEY_ID=1
D:AWS_SECRET_ACCESS_KEY=1

[coverage:run]
branch = True
Expand Down
56 changes: 56 additions & 0 deletions tests/integer_set_attribute_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from typing import Set

import pytest
from pynamodb.attributes import UnicodeAttribute
from pynamodb.models import Model
from typing_extensions import assert_type

from pynamodb_attributes import IntegerSetAttribute
from tests.connection import _connection
from tests.meta import dynamodb_table_meta


class MyModel(Model):
Meta = dynamodb_table_meta(__name__)

key = UnicodeAttribute(hash_key=True)
value = IntegerSetAttribute(null=True)


assert_type(MyModel.value, IntegerSetAttribute)
assert_type(MyModel().value, Set[int])


@pytest.fixture(scope="module", autouse=True)
def create_table():
MyModel.create_table()


def test_serialization_non_null(uuid_key):
model = MyModel()
model.key = uuid_key
model.value = {456, 789}
model.save()

# verify underlying storage
item = _connection(MyModel).get_item(uuid_key)
assert item["Item"]["value"] == {"NS": ["456", "789"]}

# verify deserialization
model = MyModel.get(uuid_key)
assert model.value == {456, 789}


def test_serialization_null(uuid_key):
model = MyModel()
model.key = uuid_key
model.value = None
model.save()

# verify underlying storage
item = _connection(MyModel).get_item(uuid_key)
assert "value" not in item["Item"]

# verify deserialization
model = MyModel.get(uuid_key)
assert model.value is None
1 change: 1 addition & 0 deletions tests/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

def dynamodb_table_meta(table_suffix):
class Meta:
region = os.getenv("DYNAMODB_REGION", "us-east-1")
host = os.getenv("DYNAMODB_URL", "http://localhost:8000")
table_name = f"pynamodb-attributes-{table_suffix}"
read_capacity_units = 10
Expand Down

0 comments on commit 1a74dea

Please sign in to comment.