Skip to content

Commit

Permalink
Upgrade to mypy 0.950 (#1116)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ikonst authored Nov 18, 2022
1 parent b004829 commit f6f1b4d
Show file tree
Hide file tree
Showing 16 changed files with 319 additions and 307 deletions.
12 changes: 9 additions & 3 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
.. highlight:: none

Release Notes
=============

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

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

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


v5.3.0
----------
Expand Down Expand Up @@ -146,7 +150,7 @@ v4.3.3

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

::
.. code-block:: python
class MyModel(Model):
...
Expand Down Expand Up @@ -228,7 +232,9 @@ v4.1.0

This is a backwards compatible, minor release.

* In the Model's Meta, you may now provide an AWS session token, which is mostly useful for assumed roles (#700)::
* In the Model's Meta, you may now provide an AWS session token, which is mostly useful for assumed roles (#700):

.. code-block:: python
sts_client = boto3.client("sts")
role_object = sts_client.assume_role(RoleArn=role_arn, RoleSessionName="role_name", DurationSeconds=BOTO3_CLIENT_DURATION)
Expand Down
9 changes: 7 additions & 2 deletions examples/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
A PynamoDB example using a custom attribute
"""
import pickle
from pynamodb.attributes import BinaryAttribute, UnicodeAttribute
from typing import Any

from pynamodb.attributes import Attribute, UnicodeAttribute
from pynamodb.constants import BINARY
from pynamodb.models import Model


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


class PickleAttribute(BinaryAttribute):
class PickleAttribute(Attribute[Any]):
attr_type = BINARY

"""
This class will serializer/deserialize any picklable Python object.
The value will be stored as a binary attribute in DynamoDB.
Expand Down
9 changes: 5 additions & 4 deletions examples/indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,17 @@ class Meta:
player_opponent_index = GamePlayerOpponentIndex()
opponent_time_index = GameOpponentTimeIndex()


if not GameModel.exists():
GameModel.create_table(wait=True)

# Create an item
item = GameModel('1234', datetime.datetime.utcnow())
item.winner_id = '5678'
item.save()
game = GameModel('1234', datetime.datetime.utcnow())
game.winner_id = '5678'
game.save()

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

# Count on an index
Expand Down
69 changes: 38 additions & 31 deletions examples/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SampleTablesAndData.html
"""
import logging
from typing import Any

from pynamodb.models import Model
from pynamodb.attributes import (
UnicodeAttribute, NumberAttribute, UnicodeSetAttribute, UTCDateTimeAttribute
ListAttribute,
NumberAttribute,
UnicodeAttribute,
UnicodeSetAttribute,
UTCDateTimeAttribute,
)
from datetime import datetime

Expand All @@ -29,7 +35,7 @@ class Meta:
answered = NumberAttribute(default=0)
tags = UnicodeSetAttribute()
last_post_datetime = UTCDateTimeAttribute(null=True)
notes = ListAttribute(default=list)
notes: ListAttribute[Any] = ListAttribute(default=list)


# Delete the table
Expand Down Expand Up @@ -60,7 +66,7 @@ class Meta:
threads = []
for x in range(100):
thread = Thread('forum-{0}'.format(x), 'subject-{0}'.format(x))
thread.tags = ['tag1', 'tag2']
thread.tags = {'tag1', 'tag2'}
thread.last_post_datetime = datetime.now()
threads.append(thread)

Expand All @@ -75,16 +81,16 @@ class Meta:

# Batch get
item_keys = [('forum-{0}'.format(x), 'subject-{0}'.format(x)) for x in range(100)]
for item in Thread.batch_get(item_keys):
print(item)
for thread_item in Thread.batch_get(item_keys):
print(thread_item)

# Scan
for item in Thread.scan():
print(item)
for thread_item in Thread.scan():
print(thread_item)

# Query
for item in Thread.query('forum-1', Thread.subject.startswith('subject')):
print(item)
for thread_item in Thread.query('forum-1', Thread.subject.startswith('subject')):
print(thread_item)


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


if not AliasedModel.exists():
AliasedModel.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)

# Create a thread
thread_item = AliasedModel(
aliased_thread_item = AliasedModel(
'Some Forum',
'Some Subject',
tags=['foo', 'bar'],
last_post_datetime=datetime.now()
)

# Save the thread
thread_item.save()
aliased_thread_item.save()

# Batch write operation
with AliasedModel.batch_write() as batch:
threads = []
for x in range(100):
thread = AliasedModel('forum-{0}'.format(x), 'subject-{0}'.format(x))
thread.tags = ['tag1', 'tag2']
thread.last_post_datetime = datetime.now()
threads.append(thread)
aliased_threads = []
for idx in range(100):
aliased_thread_item = AliasedModel('forum-{0}'.format(idx), 'subject-{0}'.format(idx))
aliased_thread_item.tags = {'tag1', 'tag2'}
aliased_thread_item.last_post_datetime = datetime.now()
aliased_threads.append(aliased_thread_item)

for thread in threads:
batch.save(thread)
for aliased_thread_item in aliased_threads:
batch.save(aliased_thread_item)

# Batch get
item_keys = [('forum-{0}'.format(x), 'subject-{0}'.format(x)) for x in range(100)]
for item in AliasedModel.batch_get(item_keys):
print("Batch get item: {0}".format(item))
for aliased_thread_item in AliasedModel.batch_get(item_keys):
print("Batch get item: {0}".format(aliased_thread_item))

# Scan
for item in AliasedModel.scan():
print("Scanned item: {0}".format(item))
for aliased_thread_item in AliasedModel.scan():
print("Scanned item: {0}".format(aliased_thread_item))

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

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


# Scan with filters
for item in Thread.scan(Thread.subject.startswith('subject') & (Thread.views == 0)):
print("Scanned item: {0} {1}".format(item.subject, item.views))
for thread_item in Thread.scan(Thread.subject.startswith('subject') & (Thread.views == 0)):
print("Scanned item: {0} {1}".format(thread_item.subject, thread_item.views))

# Scan with null filter
for item in Thread.scan(Thread.subject.startswith('subject') & Thread.last_post_datetime.does_not_exist()):
print("Scanned item: {0} {1}".format(item.subject, item.views))
for thread_item in Thread.scan(Thread.subject.startswith('subject') & Thread.last_post_datetime.does_not_exist()):
print("Scanned item: {0} {1}".format(thread_item.subject, thread_item.views))

# Conditionally save an item
thread_item = Thread(
Expand Down
2 changes: 1 addition & 1 deletion examples/optimistic_locking.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def assert_condition_check_fails():
except TransactWriteError as e:
assert isinstance(e.cause, ClientError)
assert e.cause_response_code == "TransactionCanceledException"
assert "ConditionalCheckFailed" in e.cause_response_message
assert "ConditionalCheckFailed" in (e.cause_response_message or '')
else:
raise AssertionError("The version attribute conditional check should have failed.")

Expand Down
4 changes: 4 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ warn_incomplete_stub = True
follow_imports = normal
show_error_codes = True

# Ignore errors in the docs/conf.py file
[mypy-conf]
ignore_errors = True

# TODO: burn these down
[mypy-tests.*]
ignore_errors = True
2 changes: 1 addition & 1 deletion pynamodb/indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Index(Generic[_M]):

@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs) # type: ignore # see https://github.com/python/mypy/issues/4660
super().__init_subclass__(**kwargs)
if cls.Meta is not None:
cls.Meta.attributes = {}
for name, attribute in getmembers(cls, lambda o: isinstance(o, Attribute)):
Expand Down
2 changes: 1 addition & 1 deletion pynamodb/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
def _load_module(name, path):
# https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
spec = importlib.util.spec_from_file_location(name, path)
module = importlib.util.module_from_spec(spec)
module = importlib.util.module_from_spec(spec) # type: ignore
spec.loader.exec_module(module) # type: ignore
return module

Expand Down
4 changes: 2 additions & 2 deletions pynamodb/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ def __exit__(self, exc_type, exc_val, exc_tb):
self._commit()


class TransactGet(Generic[_M], Transaction):
class TransactGet(Transaction):

_results: Optional[List] = None

def __init__(self, *args, **kwargs):
def __init__(self, *args: Any, **kwargs: Any) -> None:
self._get_items: List[Dict] = []
self._futures: List[_ModelFuture] = []
super(TransactGet, self).__init__(*args, **kwargs)
Expand Down
3 changes: 2 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ pytest-mock

# only used in CI
coveralls
mypy==0.770;python_version>="3.7"
mypy==0.950;python_version>="3.7"
pytest-cov

# used for type-checking
botocore-stubs
types-Flask
10 changes: 0 additions & 10 deletions tests/conftest.py

This file was deleted.

Loading

0 comments on commit f6f1b4d

Please sign in to comment.