Search code examples
pythonamazon-dynamodbboto3python-3.8moto

Teardown issue using Moto DynamoDB and unittest in Python 3.8


I'm trying to run some unit tests using moto and unittest based off of this example from muhannad0's blog.

Below is my code (minified the table creation as it's not so important).

@mock_dynamodb2
class TestDatabaseFunctions(unittest.TestCase):

    def setUp(self):
        """
        Create database resource and mock table
        """
        print("Setting up")
        self.dynamodb = boto3.resource('dynamodb', region_name='eu-west-2')

        self.table = self.dynamodb.create_table(TableName='test-table', KeySchema=[{'AttributeName': 'pk', 'KeyType': 'HASH'}, {'AttributeName': 'sk','KeyType': 'RANGE'}], AttributeDefinitions=[{'AttributeName': 'pk', 'AttributeType': 'S'},{'AttributeName': 'sk', 'AttributeType': 'S'}], ProvisionedThroughput={'ReadCapacityUnits': 1, 'WriteCapacityUnits': 1})

        print("Waiting until the table exists")
        # Wait until the table exists.
        self.table.meta.client.get_waiter('table_exists').wait(TableName='test-table')
        assert self.table.table_status == 'ACTIVE'

        print("Ready to go")

    def tearDown(self):
        """
        Delete database resource and mock table
        """
        print("Tearing down")
        self.table.delete()
        self.dynamodb = None
        print("Teardown complete")

    def test_table_exists(self):
        """
        Test if our mock table is ready
        """
        print("Testing")
        self.assertIn('test-table', self.table.name)
        print("Test complete")


if __name__ == '__main__':
    unittest.main()

When I run it I end up with an error deep in Python 3.8's mock.py file.

=================================== FAILURES ===================================
___________________ TestDatabaseFunctions.test_table_exists ____________________
../../../env/lib/python3.8/site-packages/moto/core/models.py:102: in wrapper
    self.stop()
../../../env/lib/python3.8/site-packages/moto/core/models.py:86: in stop
    self.default_session_mock.stop()
../../../env/lib/python3.8/site-packages/mock/mock.py:1563: in stop
    return self.__exit__(None, None, None)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <mock.mock._patch object at 0x1128d2a30>, exc_info = (None, None, None)

    def __exit__(self, *exc_info):
        """Undo the patch."""
>       if self.is_local and self.temp_original is not DEFAULT:
E       AttributeError: '_patch' object has no attribute 'is_local'

../../../env/lib/python3.8/site-packages/mock/mock.py:1529: AttributeError

Thanks to my caveman debugging I can say that this error happens after the Teardown complete message, suggesting that this is happening after the test executes successfully and is only happening after my teardown block finishes up.

I quite like this example by muhannad0 as it uses the class decorator and lets us mock dynamodb in there easily so hopefully we can keep it.

Let me know if you need any more information, you should be able to run this yourself by copying and pasting the code into your preferred IDE and hitting go.


Solution

  • This looks like it's due to an incompatibility between the moto and mock libraries. The issue is being discussed here: https://github.com/spulec/moto/issues/3535

    A temporary workaround is to fix those libraries to versions that are compatible. I'm currently fixing mock to 4.0.2 to avoid the AttributeError:

    pip install mock==4.0.2