Skip to content

Commit f6f1b4d

Browse files
authored
Upgrade to mypy 0.950 (#1116)
mypy<0.900 is dragging in typed-ast which no longer seems to build on Python 3.11. In order to unblock the release of 5.3.1, we'll pull up to mypy==0.950 (for assert_type) and drag in some minor (non-breaking) improvements from master.
1 parent b004829 commit f6f1b4d

16 files changed

+319
-307
lines changed

docs/release_notes.rst

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1+
.. highlight:: none
2+
13
Release Notes
24
=============
35

46
v5.3.1
57
----------
6-
* Fixed issue introduced in 5.3.0: using TableConnection directly (not through a model)
8+
* Fixed issue introduced in 5.3.0: using :py:class:`~pynamodb.connection.table.TableConnection` directly (not through a model)
79
raised the following exception::
810

911
pynamodb.exceptions.TableError: Meta-table for '(table-name)' not initialized
1012

13+
* Fix typing on :py:class:`~pynamodb.transactions.TransactGet` (backport of #1057)
14+
1115

1216
v5.3.0
1317
----------
@@ -146,7 +150,7 @@ v4.3.3
146150

147151
* Add type stubs for indexing into a ``ListAttribute`` for forming conditional expressions (#774)
148152

149-
::
153+
.. code-block:: python
150154
151155
class MyModel(Model):
152156
...
@@ -228,7 +232,9 @@ v4.1.0
228232

229233
This is a backwards compatible, minor release.
230234

231-
* In the Model's Meta, you may now provide an AWS session token, which is mostly useful for assumed roles (#700)::
235+
* In the Model's Meta, you may now provide an AWS session token, which is mostly useful for assumed roles (#700):
236+
237+
.. code-block:: python
232238
233239
sts_client = boto3.client("sts")
234240
role_object = sts_client.assume_role(RoleArn=role_arn, RoleSessionName="role_name", DurationSeconds=BOTO3_CLIENT_DURATION)

examples/attributes.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
A PynamoDB example using a custom attribute
33
"""
44
import pickle
5-
from pynamodb.attributes import BinaryAttribute, UnicodeAttribute
5+
from typing import Any
6+
7+
from pynamodb.attributes import Attribute, UnicodeAttribute
8+
from pynamodb.constants import BINARY
69
from pynamodb.models import Model
710

811

@@ -17,7 +20,9 @@ def __str__(self):
1720
return "<Color: {}>".format(self.name)
1821

1922

20-
class PickleAttribute(BinaryAttribute):
23+
class PickleAttribute(Attribute[Any]):
24+
attr_type = BINARY
25+
2126
"""
2227
This class will serializer/deserialize any picklable Python object.
2328
The value will be stored as a binary attribute in DynamoDB.

examples/indexes.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,17 @@ class Meta:
8686
player_opponent_index = GamePlayerOpponentIndex()
8787
opponent_time_index = GameOpponentTimeIndex()
8888

89+
8990
if not GameModel.exists():
9091
GameModel.create_table(wait=True)
9192

9293
# Create an item
93-
item = GameModel('1234', datetime.datetime.utcnow())
94-
item.winner_id = '5678'
95-
item.save()
94+
game = GameModel('1234', datetime.datetime.utcnow())
95+
game.winner_id = '5678'
96+
game.save()
9697

9798
# Indexes can be queried easily using the index's hash key
98-
for item in GameModel.player_opponent_index.query('1234'):
99+
for game in GameModel.player_opponent_index.query('1234'):
99100
print("Item queried from index: {0}".format(item))
100101

101102
# Count on an index

examples/model.py

+38-31
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SampleTablesAndData.html
55
"""
66
import logging
7+
from typing import Any
8+
79
from pynamodb.models import Model
810
from pynamodb.attributes import (
9-
UnicodeAttribute, NumberAttribute, UnicodeSetAttribute, UTCDateTimeAttribute
11+
ListAttribute,
12+
NumberAttribute,
13+
UnicodeAttribute,
14+
UnicodeSetAttribute,
15+
UTCDateTimeAttribute,
1016
)
1117
from datetime import datetime
1218

@@ -29,7 +35,7 @@ class Meta:
2935
answered = NumberAttribute(default=0)
3036
tags = UnicodeSetAttribute()
3137
last_post_datetime = UTCDateTimeAttribute(null=True)
32-
notes = ListAttribute(default=list)
38+
notes: ListAttribute[Any] = ListAttribute(default=list)
3339

3440

3541
# Delete the table
@@ -60,7 +66,7 @@ class Meta:
6066
threads = []
6167
for x in range(100):
6268
thread = Thread('forum-{0}'.format(x), 'subject-{0}'.format(x))
63-
thread.tags = ['tag1', 'tag2']
69+
thread.tags = {'tag1', 'tag2'}
6470
thread.last_post_datetime = datetime.now()
6571
threads.append(thread)
6672

@@ -75,16 +81,16 @@ class Meta:
7581

7682
# Batch get
7783
item_keys = [('forum-{0}'.format(x), 'subject-{0}'.format(x)) for x in range(100)]
78-
for item in Thread.batch_get(item_keys):
79-
print(item)
84+
for thread_item in Thread.batch_get(item_keys):
85+
print(thread_item)
8086

8187
# Scan
82-
for item in Thread.scan():
83-
print(item)
88+
for thread_item in Thread.scan():
89+
print(thread_item)
8490

8591
# Query
86-
for item in Thread.query('forum-1', Thread.subject.startswith('subject')):
87-
print(item)
92+
for thread_item in Thread.query('forum-1', Thread.subject.startswith('subject')):
93+
print(thread_item)
8894

8995

9096
print("-"*80)
@@ -103,57 +109,58 @@ class Meta:
103109
tags = UnicodeSetAttribute(attr_name='t')
104110
last_post_datetime = UTCDateTimeAttribute(attr_name='lp')
105111

112+
106113
if not AliasedModel.exists():
107114
AliasedModel.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)
108115

109116
# Create a thread
110-
thread_item = AliasedModel(
117+
aliased_thread_item = AliasedModel(
111118
'Some Forum',
112119
'Some Subject',
113120
tags=['foo', 'bar'],
114121
last_post_datetime=datetime.now()
115122
)
116123

117124
# Save the thread
118-
thread_item.save()
125+
aliased_thread_item.save()
119126

120127
# Batch write operation
121128
with AliasedModel.batch_write() as batch:
122-
threads = []
123-
for x in range(100):
124-
thread = AliasedModel('forum-{0}'.format(x), 'subject-{0}'.format(x))
125-
thread.tags = ['tag1', 'tag2']
126-
thread.last_post_datetime = datetime.now()
127-
threads.append(thread)
129+
aliased_threads = []
130+
for idx in range(100):
131+
aliased_thread_item = AliasedModel('forum-{0}'.format(idx), 'subject-{0}'.format(idx))
132+
aliased_thread_item.tags = {'tag1', 'tag2'}
133+
aliased_thread_item.last_post_datetime = datetime.now()
134+
aliased_threads.append(aliased_thread_item)
128135

129-
for thread in threads:
130-
batch.save(thread)
136+
for aliased_thread_item in aliased_threads:
137+
batch.save(aliased_thread_item)
131138

132139
# Batch get
133140
item_keys = [('forum-{0}'.format(x), 'subject-{0}'.format(x)) for x in range(100)]
134-
for item in AliasedModel.batch_get(item_keys):
135-
print("Batch get item: {0}".format(item))
141+
for aliased_thread_item in AliasedModel.batch_get(item_keys):
142+
print("Batch get item: {0}".format(aliased_thread_item))
136143

137144
# Scan
138-
for item in AliasedModel.scan():
139-
print("Scanned item: {0}".format(item))
145+
for aliased_thread_item in AliasedModel.scan():
146+
print("Scanned item: {0}".format(aliased_thread_item))
140147

141148
# Query
142-
for item in AliasedModel.query('forum-1', AliasedModel.subject.startswith('subject')):
143-
print("Query using aliased attribute: {0}".format(item))
149+
for aliased_thread_item in AliasedModel.query('forum-1', AliasedModel.subject.startswith('subject')):
150+
print("Query using aliased attribute: {0}".format(aliased_thread_item))
144151

145152
# Query with filters
146-
for item in Thread.query('forum-1', (Thread.views == 0) | (Thread.replies == 0)):
147-
print("Query result: {0}".format(item))
153+
for thread_item in Thread.query('forum-1', (Thread.views == 0) | (Thread.replies == 0)):
154+
print("Query result: {0}".format(thread_item))
148155

149156

150157
# Scan with filters
151-
for item in Thread.scan(Thread.subject.startswith('subject') & (Thread.views == 0)):
152-
print("Scanned item: {0} {1}".format(item.subject, item.views))
158+
for thread_item in Thread.scan(Thread.subject.startswith('subject') & (Thread.views == 0)):
159+
print("Scanned item: {0} {1}".format(thread_item.subject, thread_item.views))
153160

154161
# Scan with null filter
155-
for item in Thread.scan(Thread.subject.startswith('subject') & Thread.last_post_datetime.does_not_exist()):
156-
print("Scanned item: {0} {1}".format(item.subject, item.views))
162+
for thread_item in Thread.scan(Thread.subject.startswith('subject') & Thread.last_post_datetime.does_not_exist()):
163+
print("Scanned item: {0} {1}".format(thread_item.subject, thread_item.views))
157164

158165
# Conditionally save an item
159166
thread_item = Thread(

examples/optimistic_locking.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def assert_condition_check_fails():
4646
except TransactWriteError as e:
4747
assert isinstance(e.cause, ClientError)
4848
assert e.cause_response_code == "TransactionCanceledException"
49-
assert "ConditionalCheckFailed" in e.cause_response_message
49+
assert "ConditionalCheckFailed" in (e.cause_response_message or '')
5050
else:
5151
raise AssertionError("The version attribute conditional check should have failed.")
5252

mypy.ini

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ warn_incomplete_stub = True
1010
follow_imports = normal
1111
show_error_codes = True
1212

13+
# Ignore errors in the docs/conf.py file
14+
[mypy-conf]
15+
ignore_errors = True
16+
1317
# TODO: burn these down
1418
[mypy-tests.*]
1519
ignore_errors = True

pynamodb/indexes.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Index(Generic[_M]):
3030

3131
@classmethod
3232
def __init_subclass__(cls, **kwargs):
33-
super().__init_subclass__(**kwargs) # type: ignore # see https://github.com/python/mypy/issues/4660
33+
super().__init_subclass__(**kwargs)
3434
if cls.Meta is not None:
3535
cls.Meta.attributes = {}
3636
for name, attribute in getmembers(cls, lambda o: isinstance(o, Attribute)):

pynamodb/settings.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
def _load_module(name, path):
2525
# https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
2626
spec = importlib.util.spec_from_file_location(name, path)
27-
module = importlib.util.module_from_spec(spec)
27+
module = importlib.util.module_from_spec(spec) # type: ignore
2828
spec.loader.exec_module(module) # type: ignore
2929
return module
3030

pynamodb/transactions.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ def __exit__(self, exc_type, exc_val, exc_tb):
3131
self._commit()
3232

3333

34-
class TransactGet(Generic[_M], Transaction):
34+
class TransactGet(Transaction):
3535

3636
_results: Optional[List] = None
3737

38-
def __init__(self, *args, **kwargs):
38+
def __init__(self, *args: Any, **kwargs: Any) -> None:
3939
self._get_items: List[Dict] = []
4040
self._futures: List[_ModelFuture] = []
4141
super(TransactGet, self).__init__(*args, **kwargs)

requirements-dev.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ pytest-mock
44

55
# only used in CI
66
coveralls
7-
mypy==0.770;python_version>="3.7"
7+
mypy==0.950;python_version>="3.7"
88
pytest-cov
99

1010
# used for type-checking
1111
botocore-stubs
12+
types-Flask

tests/conftest.py

-10
This file was deleted.

0 commit comments

Comments
 (0)