Skip to content

Commit 105b256

Browse files
author
Janos Tolgyesi
committed
Linter + code style
1 parent 3300cf5 commit 105b256

File tree

3 files changed

+131
-51
lines changed

3 files changed

+131
-51
lines changed

dynamodb_mapping/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
from .dynamodb_mapping import DynamoDBMapping, DynamoDBKeySimplified, DynamoDBItemType
66

77
__author__ = """Janos Tolgyesi"""
8-
__email__ = 'janos.tolgyesi@gmail.com'
9-
__version__ = '0.1.0'
10-
__all__ = ['DynamoDBMapping', 'DynamoDBKeySimplified', 'DynamoDBItemType']
8+
__email__ = "janos.tolgyesi@gmail.com"
9+
__version__ = "0.1.0"
10+
__all__ = ["DynamoDBMapping", "DynamoDBKeySimplified", "DynamoDBItemType"]

dynamodb_mapping/dynamodb_mapping.py

Lines changed: 77 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,18 @@
44
from __future__ import annotations
55

66
from typing import (
7-
Iterator, Tuple, Union, Any, Optional, Iterable, Dict, Set, List, Mapping, Sequence,
8-
cast
7+
Iterator,
8+
Tuple,
9+
Union,
10+
Any,
11+
Optional,
12+
Iterable,
13+
Dict,
14+
Set,
15+
List,
16+
Mapping,
17+
Sequence,
18+
cast,
919
)
1020
from collections.abc import ValuesView, ItemsView, KeysView, MutableMapping
1121
from decimal import Decimal
@@ -17,6 +27,7 @@
1727

1828
try:
1929
import mypy_boto3_dynamodb
30+
2031
DynamoDBTable = mypy_boto3_dynamodb.service_resource.Table
2132
except ImportError:
2233
DynamoDBTable = Any # type: ignore
@@ -44,15 +55,38 @@
4455
"""DynamoDB primary key name type"""
4556

4657
DynamoDBValueTypes = (
47-
str, int, Decimal, Binary, bytes, bytearray, bool, None,
48-
Set[str], Set[int], Set[Decimal], Set[Binary], List, Dict
58+
str,
59+
int,
60+
Decimal,
61+
Binary,
62+
bytes,
63+
bytearray,
64+
bool,
65+
None,
66+
Set[str],
67+
Set[int],
68+
Set[Decimal],
69+
Set[Binary],
70+
List,
71+
Dict,
4972
)
5073
"""DynamoDB value type choices."""
5174

5275
DynamoDBValue = Union[
53-
bytes, bytearray, str, int, Decimal, bool,
54-
Set[int], Set[Decimal], Set[str], Set[bytes], Set[bytearray],
55-
Sequence[Any], Mapping[str, Any], None,
76+
bytes,
77+
bytearray,
78+
str,
79+
int,
80+
Decimal,
81+
bool,
82+
Set[int],
83+
Set[Decimal],
84+
Set[str],
85+
Set[bytes],
86+
Set[bytearray],
87+
Sequence[Any],
88+
Mapping[str, Any],
89+
None,
5690
]
5791
"""DynamoDB value type."""
5892

@@ -68,7 +102,7 @@ def _boto3_session_from_config(config: Dict[str, Any]) -> Optional[boto3.Session
68102
aws_access_key_id=config["aws_access_key_id"],
69103
aws_secret_access_key=config["aws_secret_access_key"],
70104
region_name=config.get("aws_region"),
71-
profile_name=config.get("aws_profile")
105+
profile_name=config.get("aws_profile"),
72106
)
73107
else:
74108
return None
@@ -84,8 +118,10 @@ def get_key_names(table: DynamoDBTable) -> DynamoDBKeyName:
84118
DynamoDBKeyName: A tuple with either one (if only the partition key is defined on the table)
85119
or two (if both the partition and range key is defined) elements.
86120
"""
87-
schema: Dict[str, str] = {s["KeyType"]: s["AttributeName"] for s in table.key_schema}
88-
return (schema["HASH"], schema["RANGE"]) if "RANGE" in schema else (schema["HASH"], )
121+
schema: Dict[str, str] = {
122+
s["KeyType"]: s["AttributeName"] for s in table.key_schema
123+
}
124+
return (schema["HASH"], schema["RANGE"]) if "RANGE" in schema else (schema["HASH"],)
89125

90126

91127
def simplify_tuple_keys(key: DynamoDBKeyAny) -> DynamoDBKeySimplified:
@@ -287,22 +323,29 @@ class DynamoDBMapping(MutableMapping):
287323
"""
288324

289325
def __init__(
290-
self, table_name: str, boto3_session: Optional[boto3.session.Session] = None, **kwargs
326+
self,
327+
table_name: str,
328+
boto3_session: Optional[boto3.session.Session] = None,
329+
**kwargs,
291330
) -> None:
292331
session = (
293-
boto3_session or
294-
kwargs.get("boto3_session") or
295-
_boto3_session_from_config(kwargs) or
296-
boto3.Session()
332+
boto3_session
333+
or kwargs.get("boto3_session")
334+
or _boto3_session_from_config(kwargs)
335+
or boto3.Session()
297336
)
298337
dynamodb = session.resource("dynamodb")
299338
self.table = dynamodb.Table(table_name)
300339
self.key_names = get_key_names(self.table)
301340

302-
def _create_key_param(self, keys: DynamoDBKeySimplified) -> Dict[str, DynamoDBKeyPrimitive]:
341+
def _create_key_param(
342+
self, keys: DynamoDBKeySimplified
343+
) -> Dict[str, DynamoDBKeyPrimitive]:
303344
tuple_keys = create_tuple_keys(keys)
304345
if len(tuple_keys) != len(self.key_names):
305-
raise ValueError(f"You must provide a value for each of {self.key_names} keys.")
346+
raise ValueError(
347+
f"You must provide a value for each of {self.key_names} keys."
348+
)
306349
param = {name: value for name, value in zip(self.key_names, tuple_keys)}
307350
return param
308351

@@ -370,7 +413,9 @@ def get_item(self, keys: DynamoDBKeySimplified, **kwargs) -> DynamoDBItemAccesso
370413
data = response["Item"]
371414
return DynamoDBItemAccessor(parent=self, item_keys=keys, initial_data=data)
372415

373-
def set_item(self, keys: DynamoDBKeySimplified, item: DynamoDBItemType, **kwargs) -> None:
416+
def set_item(
417+
self, keys: DynamoDBKeySimplified, item: DynamoDBItemType, **kwargs
418+
) -> None:
374419
"""Create or overwrite a single item in the table.
375420
376421
Example::
@@ -391,11 +436,15 @@ def set_item(self, keys: DynamoDBKeySimplified, item: DynamoDBItemType, **kwargs
391436
logger.debug("Performing a put_item operation on %s table", self.table.name)
392437
self.table.put_item(Item=_item, **kwargs)
393438

394-
def put_item(self, keys: DynamoDBKeySimplified, item: DynamoDBItemType, **kwargs) -> None:
439+
def put_item(
440+
self, keys: DynamoDBKeySimplified, item: DynamoDBItemType, **kwargs
441+
) -> None:
395442
"""An alias for the ``set_item`` method."""
396443
self.set_item(keys, item, **kwargs)
397444

398-
def del_item(self, keys: DynamoDBKeySimplified, check_existing=True, **kwargs) -> None:
445+
def del_item(
446+
self, keys: DynamoDBKeySimplified, check_existing=True, **kwargs
447+
) -> None:
399448
"""Delete a single item from the table.
400449
401450
Example::
@@ -419,10 +468,7 @@ def del_item(self, keys: DynamoDBKeySimplified, check_existing=True, **kwargs) -
419468
self.table.delete_item(Key=key_params, **kwargs)
420469

421470
def modify_item(
422-
self,
423-
keys: DynamoDBKeySimplified,
424-
modifications: DynamoDBItemType,
425-
**kwargs
471+
self, keys: DynamoDBKeySimplified, modifications: DynamoDBItemType, **kwargs
426472
) -> None:
427473
"""Modify the properties of an existing item.
428474
@@ -459,9 +505,14 @@ def modify_item(
459505
if set_expression_parts:
460506
update_expression_parts.append("set " + ", ".join(set_expression_parts))
461507
if remove_expression_parts:
462-
update_expression_parts.append("remove " + ", ".join(remove_expression_parts))
508+
update_expression_parts.append(
509+
"remove " + ", ".join(remove_expression_parts)
510+
)
463511
if not update_expression_parts:
464-
warning_msg = "No update expression was created by modify_item: modifications mapping is empty?"
512+
warning_msg = (
513+
"No update expression was created by modify_item: "
514+
"modifications mapping is empty?"
515+
)
465516
warnings.warn(warning_msg, UserWarning)
466517
logger.warning(warning_msg)
467518
return

tests/test_dynamodb_mapping.py

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,14 @@
99
TEST_TABLE_HASH_KEY_NAME = "test_primary_key"
1010

1111
TEST_ITEM1_KEY = "first_item"
12-
TEST_ITEM1 = {
13-
TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY,
14-
"foo": "bar"
15-
}
12+
TEST_ITEM1 = {TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY, "foo": "bar"}
1613

1714
TEST_ITEM2_KEY = "second_item"
18-
TEST_ITEM2 = {
19-
TEST_TABLE_HASH_KEY_NAME: TEST_ITEM2_KEY,
20-
"foo2": "bar2"
21-
}
15+
TEST_ITEM2 = {TEST_TABLE_HASH_KEY_NAME: TEST_ITEM2_KEY, "foo2": "bar2"}
2216

2317
TEST_ATTRIBUTES = {"foo": "bar"}
2418

19+
2520
@pytest.fixture
2621
def mapping(mocker):
2722
boto3_session = mocker.MagicMock()
@@ -34,122 +29,156 @@ def mapping(mocker):
3429
def test_init(mapping):
3530
assert mapping.key_names == (TEST_TABLE_HASH_KEY_NAME,)
3631

32+
3733
def test_scan(mapping, mocker):
3834
mapping.table.scan = mocker.MagicMock(return_value={"Items": [TEST_ITEM1]})
3935
assert next(mapping.scan()) == TEST_ITEM1
4036

37+
4138
def test_scan_pages(mapping, mocker):
42-
mapping.table.scan = mocker.MagicMock(side_effect=[
43-
{"Items": [TEST_ITEM1], "LastEvaluatedKey": "to_be_continued"}, {"Items": [TEST_ITEM2]}
44-
])
39+
mapping.table.scan = mocker.MagicMock(
40+
side_effect=[
41+
{"Items": [TEST_ITEM1], "LastEvaluatedKey": "to_be_continued"},
42+
{"Items": [TEST_ITEM2]},
43+
]
44+
)
4545
results = mapping.scan()
4646
assert next(results) == TEST_ITEM1
4747
assert next(results) == TEST_ITEM2
4848
assert mapping.table.scan.call_count == 2
4949

50+
5051
def test_get_item(mapping, mocker):
5152
mapping.table.get_item = mocker.MagicMock(return_value={"Item": TEST_ITEM1})
5253
assert mapping.get_item(TEST_ITEM1_KEY) == TEST_ITEM1
53-
mapping.table.get_item.assert_called_with(Key={TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY})
54+
mapping.table.get_item.assert_called_with(
55+
Key={TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY}
56+
)
57+
5458

5559
def test_invalid_keys(mapping):
5660
with pytest.raises(ValueError):
5761
mapping.get_item((TEST_ITEM1_KEY, TEST_ITEM2_KEY))
5862

63+
5964
def test_get_item_non_existing(mapping, mocker):
6065
mapping.table.get_item = mocker.MagicMock(return_value={})
6166
with pytest.raises(KeyError):
6267
mapping.get_item(TEST_ITEM1_KEY)
6368

69+
6470
def test_get_item_accessor(mapping, mocker):
6571
mapping.table.get_item = mocker.MagicMock(return_value={"Item": TEST_ITEM1})
6672
mapping.modify_item = mocker.MagicMock()
6773
accessor = mapping.get_item(TEST_ITEM1_KEY)
68-
mapping.table.get_item.assert_called_with(Key={TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY})
74+
mapping.table.get_item.assert_called_with(
75+
Key={TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY}
76+
)
6977
accessor["new_attrib"] = "foobar"
7078
mapping.modify_item.assert_called_with(TEST_ITEM1_KEY, {"new_attrib": "foobar"})
7179

80+
7281
def test_set_item(mapping, mocker):
7382
mapping.table.put_item = mocker.MagicMock()
7483
mapping.set_item(TEST_ITEM1_KEY, TEST_ATTRIBUTES)
7584
mapping.table.put_item.assert_called_with(
7685
Item={TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY, **TEST_ATTRIBUTES}
7786
)
7887

88+
7989
def test_put_item(mapping, mocker):
8090
mapping.set_item = mocker.MagicMock()
8191
mapping.put_item(TEST_ITEM1_KEY, TEST_ATTRIBUTES)
8292
mapping.set_item.assert_called_with(TEST_ITEM1_KEY, TEST_ATTRIBUTES)
8393

94+
8495
def test_del_item(mapping, mocker):
8596
mapping.table.delete_item = mocker.MagicMock()
8697
mapping.del_item(TEST_ITEM1_KEY, check_existing=False)
87-
mapping.table.delete_item.assert_called_with(Key={TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY})
98+
mapping.table.delete_item.assert_called_with(
99+
Key={TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY}
100+
)
101+
88102

89103
def test_del_item_non_existing(mapping, mocker):
90104
mapping.table.delete_item = mocker.MagicMock()
91105
mapping.keys = mocker.MagicMock(return_value=[TEST_ITEM2_KEY])
92106
with pytest.raises(KeyError):
93107
mapping.del_item(TEST_ITEM1_KEY)
94108

109+
95110
def test_modify_item(mapping, mocker):
96111
mapping.table.update_item = mocker.MagicMock()
97-
mapping.modify_item(TEST_ITEM1_KEY, {"new1": "foobar!", "new2": "bar_foo!", "zombie": None})
112+
mapping.modify_item(
113+
TEST_ITEM1_KEY, {"new1": "foobar!", "new2": "bar_foo!", "zombie": None}
114+
)
98115
mapping.table.update_item.assert_called_with(
99116
Key={TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY},
100-
UpdateExpression='set #key0 = :value0, #key1 = :value1 remove #key2',
101-
ExpressionAttributeValues={':value0': 'foobar!', ':value1': 'bar_foo!'},
102-
ExpressionAttributeNames={'#key0': 'new1', '#key1': 'new2', '#key2': 'zombie'},
117+
UpdateExpression="set #key0 = :value0, #key1 = :value1 remove #key2",
118+
ExpressionAttributeValues={":value0": "foobar!", ":value1": "bar_foo!"},
119+
ExpressionAttributeNames={"#key0": "new1", "#key1": "new2", "#key2": "zombie"},
103120
)
104121

122+
105123
def test_modify_empty(mapping):
106124
with pytest.warns(UserWarning):
107125
mapping.modify_item(TEST_ITEM1_KEY, {})
108126

127+
109128
def test_op_iter(mapping, mocker):
110-
mapping.scan = mocker.MagicMock(return_value=[
111-
{TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY},
112-
{TEST_TABLE_HASH_KEY_NAME: TEST_ITEM2_KEY},
113-
])
129+
mapping.scan = mocker.MagicMock(
130+
return_value=[
131+
{TEST_TABLE_HASH_KEY_NAME: TEST_ITEM1_KEY},
132+
{TEST_TABLE_HASH_KEY_NAME: TEST_ITEM2_KEY},
133+
]
134+
)
114135
assert list(mapping) == [TEST_ITEM1_KEY, TEST_ITEM2_KEY]
115136
mapping.scan.assert_called_with(ProjectionExpression=TEST_TABLE_HASH_KEY_NAME)
116137

138+
117139
def test_op_len(mapping):
118140
mapping.table.item_count = 42
119141
assert len(mapping) == 42
120142

143+
121144
def test_op_getitem(mapping, mocker):
122145
mapping.get_item = mocker.MagicMock(return_value=TEST_ITEM1)
123146
assert mapping[TEST_ITEM1_KEY] == TEST_ITEM1
124147
mapping.get_item.assert_called_with(TEST_ITEM1_KEY)
125148

149+
126150
def test_op_setitem(mapping, mocker):
127151
mapping.set_item = mocker.MagicMock()
128152
mapping[TEST_ITEM1_KEY] = TEST_ITEM1
129153
mapping.set_item.assert_called_with(TEST_ITEM1_KEY, TEST_ITEM1)
130154

155+
131156
def test_op_delitem(mapping, mocker):
132157
mapping.del_item = mocker.MagicMock()
133158
del mapping[TEST_ITEM1_KEY]
134159
mapping.del_item.assert_called_with(TEST_ITEM1_KEY)
135160

161+
136162
def test_items_view(mapping, mocker):
137163
mapping.scan = mocker.MagicMock(return_value=[TEST_ITEM1, TEST_ITEM2])
138164
items = mapping.items()
139165
assert list(items) == [(TEST_ITEM1_KEY, TEST_ITEM1), (TEST_ITEM2_KEY, TEST_ITEM2)]
140166

167+
141168
def test_values_view(mapping, mocker):
142169
mapping.scan = mocker.MagicMock(return_value=[TEST_ITEM1])
143170
values = mapping.values()
144171
assert TEST_ITEM1 in values
145172
assert TEST_ITEM2 not in values
146173
assert list(values) == [TEST_ITEM1]
147174

175+
148176
def test_keys_view(mapping, mocker):
149177
mapping.table.get_item = mocker.MagicMock(side_effect=[{"Item": TEST_ITEM1}])
150178
keys = mapping.keys()
151179
assert TEST_ITEM1_KEY in keys
152180

181+
153182
def test_keys_view_non_existing(mapping, mocker):
154183
mapping.table.get_item = mocker.MagicMock(side_effect=[{}])
155184
keys = mapping.keys()

0 commit comments

Comments
 (0)