Skip to content

Commit

Permalink
Merge branch 'release-1.18.48'
Browse files Browse the repository at this point in the history
* release-1.18.48:
  Bumping version to 1.18.48
  Add changelog entries from botocore
  Declare support for Python 3.9 (#2942)
  Convert functional tests to pytest
  Convert unit tests to pytest
  Update tests for Pytest support
  use pytest instead of nose
  • Loading branch information
aws-sdk-python-automation committed Sep 24, 2021
2 parents 1f05314 + 7f75005 commit fb82bde
Show file tree
Hide file tree
Showing 43 changed files with 840 additions and 919 deletions.
12 changes: 12 additions & 0 deletions .changes/1.18.48.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"category": "``license-manager``",
"description": "[``botocore``] AWS License Manager now allows customers to get the LicenseArn in the Checkout API Response.",
"type": "api-change"
},
{
"category": "``ec2``",
"description": "[``botocore``] DescribeInstances now returns Platform Details, Usage Operation, and Usage Operation Update Time.",
"type": "api-change"
}
]
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.6, 3.7, 3.8]
python-version: [3.6, 3.7, 3.8, 3.9]
os: [ubuntu-latest, macOS-latest, windows-latest ]

steps:
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ tests/.coverage
.tox
.coverage
coverage.xml
nosetests.xml

# Common virtualenv names
venv
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
CHANGELOG
=========

1.18.48
=======

* api-change:``license-manager``: [``botocore``] AWS License Manager now allows customers to get the LicenseArn in the Checkout API Response.
* api-change:``ec2``: [``botocore``] DescribeInstances now returns Platform Details, Usage Operation, and Usage Operation Update Time.


1.18.47
=======

Expand Down
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ Running Tests
~~~~~~~~~~~~~
You can run tests in all supported Python versions using ``tox``. By default,
it will run all of the unit and functional tests, but you can also specify your own
``nosetests`` options. Note that this requires that you have all supported
``pytest`` options. Note that this requires that you have all supported
versions of Python installed, otherwise you must pass ``-e`` or run the
``nosetests`` command directly:
``pytest`` command directly:

.. code-block:: sh
Expand All @@ -98,7 +98,7 @@ You can also run individual tests with your default Python version:

.. code-block:: sh
$ nosetests tests/unit
$ pytest tests/unit
Getting Help
Expand Down
2 changes: 1 addition & 1 deletion boto3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@


__author__ = 'Amazon Web Services'
__version__ = '1.18.47'
__version__ = '1.18.48'


# The default Boto3 session; autoloaded when needed.
Expand Down
7 changes: 3 additions & 4 deletions scripts/ci/run-tests
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ def process_args(args):
test_args = ""
if args.with_cov:
test_args += (
f"--with-xunit --cover-erase --with-coverage "
f"--cover-package {PACKAGE} --cover-xml -v "
f"--cov={PACKAGE} --cov-report xml -v "
)
dirs = " ".join(args.test_dirs)

Expand All @@ -53,8 +52,8 @@ if __name__ == "__main__":
parser.add_argument(
"-r",
"--test-runner",
default="nosetests",
help="Test runner to execute tests. Defaults to nose.",
default="pytest",
help="Test runner to execute tests. Defaults to pytest.",
)
parser.add_argument(
"-c",
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ universal = 0

[metadata]
requires_dist =
botocore>=1.21.47,<1.22.0
botocore>=1.21.48,<1.22.0
jmespath>=0.7.1,<1.0.0
s3transfer>=0.5.0,<0.6.0

Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
import os
import re

from setuptools import setup, find_packages

from setuptools import find_packages, setup

ROOT = os.path.dirname(__file__)
VERSION_RE = re.compile(r'''__version__ = ['"]([0-9.]+)['"]''')


requires = [
'botocore>=1.21.47,<1.22.0',
'botocore>=1.21.48,<1.22.0',
'jmespath>=0.7.1,<1.0.0',
's3transfer>=0.5.0,<0.6.0'
]
Expand Down Expand Up @@ -54,6 +53,7 @@ def get_version():
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
],
project_urls={
'Documentation': 'https://boto3.amazonaws.com/v1/documentation/api/latest/index.html',
Expand Down
18 changes: 8 additions & 10 deletions tests/functional/docs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
class BaseDocsFunctionalTests(unittest.TestCase):
def assert_contains_lines_in_order(self, lines, contents):
for line in lines:
self.assertIn(line, contents)
assert line in contents
beginning = contents.find(line)
contents = contents[(beginning + len(line)):]

def get_class_document_block(self, class_name, contents):
start_class_document = '.. py:class:: %s' % class_name
start_index = contents.find(start_class_document)
self.assertNotEqual(start_index, -1, 'Class is not found in contents')
assert start_index != -1, 'Class is not found in contents'
contents = contents[start_index:]
end_index = contents.find(
' .. py:class::', len(start_class_document))
Expand All @@ -32,7 +32,7 @@ def get_class_document_block(self, class_name, contents):
def get_method_document_block(self, method_name, contents):
start_method_document = ' .. py:method:: %s(' % method_name
start_index = contents.find(start_method_document)
self.assertNotEqual(start_index, -1, 'Method is not found in contents')
assert start_index != -1, 'Method is not found in contents'
contents = contents[start_index:]
end_index = contents.find(
' .. py:method::', len(start_method_document))
Expand All @@ -41,8 +41,7 @@ def get_method_document_block(self, method_name, contents):
def get_request_syntax_document_block(self, contents):
start_marker = '**Request Syntax**'
start_index = contents.find(start_marker)
self.assertNotEqual(
start_index, -1, 'There is no request syntax section')
assert start_index != -1, 'There is no request syntax section'
contents = contents[start_index:]
end_index = contents.find(
':type', len(start_marker))
Expand All @@ -51,8 +50,7 @@ def get_request_syntax_document_block(self, contents):
def get_response_syntax_document_block(self, contents):
start_marker = '**Response Syntax**'
start_index = contents.find(start_marker)
self.assertNotEqual(
start_index, -1, 'There is no response syntax section')
assert start_index != -1, 'There is no response syntax section'
contents = contents[start_index:]
end_index = contents.find(
'**Response Structure**', len(start_marker))
Expand All @@ -61,19 +59,19 @@ def get_response_syntax_document_block(self, contents):
def get_request_parameter_document_block(self, param_name, contents):
start_param_document = ':type %s:' % param_name
start_index = contents.find(start_param_document)
self.assertNotEqual(start_index, -1, 'Param is not found in contents')
assert start_index != -1, 'Param is not found in contents'
contents = contents[start_index:]
end_index = contents.find(':type', len(start_param_document))
return contents[:end_index]

def get_response_parameter_document_block(self, param_name, contents):
start_param_document = '**Response Structure**'
start_index = contents.find(start_param_document)
self.assertNotEqual(start_index, -1, 'There is no response structure')
assert start_index != -1, 'There is no response structure'

start_param_document = '- **%s**' % param_name
start_index = contents.find(start_param_document)
self.assertNotEqual(start_index, -1, 'Param is not found in contents')
assert start_index != -1, 'Param is not found in contents'
contents = contents[start_index:]
end_index = contents.find('- **', len(start_param_document))
return contents[:end_index]
94 changes: 60 additions & 34 deletions tests/functional/docs/test_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
from nose.tools import assert_true
import pytest
import botocore.session
from botocore import xform_name
from botocore.exceptions import DataNotFoundError
Expand All @@ -19,50 +19,76 @@
from boto3.docs.service import ServiceDocumenter


def test_docs_generated():
"""Verify we can generate the appropriate docs for all services"""
@pytest.fixture
def botocore_session():
return botocore.session.get_session()

@pytest.fixture
def boto3_session():
return boto3.Session(region_name='us-east-1')

def all_services():
botocore_session = botocore.session.get_session()
session = boto3.Session(region_name='us-east-1')
for service_name in session.get_available_services():
generated_docs = ServiceDocumenter(
service_name, session=session).document_service()
generated_docs = generated_docs.decode('utf-8')
client = boto3.client(service_name, 'us-east-1')
yield service_name


@pytest.fixture
def available_resources():
session = boto3.Session(region_name='us-east-1')
return session.get_available_resources()


# Check that all of the services have the appropriate title
yield (_assert_has_title, generated_docs, client)
@pytest.mark.parametrize('service_name', all_services())
def test_documentation(
boto3_session, botocore_session, available_resources, service_name
):
generated_docs = ServiceDocumenter(
service_name, session=boto3_session).document_service()
generated_docs = generated_docs.decode('utf-8')
client = boto3.client(service_name, 'us-east-1')

# Check that all services have the client documented.
yield (_assert_has_client_documentation, generated_docs, service_name,
client)
# Check that all of the services have the appropriate title
_assert_has_title(generated_docs, client)

# If the client can paginate, make sure the paginators are documented.
try:
paginator_model = botocore_session.get_paginator_model(

# Check that all services have the client documented.
_assert_has_client_documentation(generated_docs, service_name, client)


#If the service has resources, make sure the service resource
#is at least documented.
if service_name in available_resources:

resource = boto3.resource(service_name, 'us-east-1')
_assert_has_resource_documentation(
generated_docs, service_name, resource
)

# If the client can paginate, make sure the paginators are documented.
try:
paginator_model = botocore_session.get_paginator_model(
service_name)
yield (_assert_has_paginator_documentation, generated_docs,
service_name, client,
sorted(paginator_model._paginator_config))
except DataNotFoundError:
pass

# If the client has waiters, make sure the waiters are documented
if client.waiter_names:
waiter_model = botocore_session.get_waiter_model(service_name)
yield (_assert_has_waiter_documentation, generated_docs,
service_name, client, waiter_model)

# If the service has resources, make sure the service resource
# is at least documented.
if service_name in session.get_available_resources():
resource = boto3.resource(service_name, 'us-east-1')
yield (_assert_has_resource_documentation, generated_docs,
service_name, resource)
_assert_has_paginator_documentation(
generated_docs, service_name, client,
sorted(paginator_model._paginator_config)
)
except DataNotFoundError:
pass


# If the client has waiters, make sure the waiters are documented.
if client.waiter_names:
waiter_model = botocore_session.get_waiter_model(service_name)
_assert_has_waiter_documentation(
generated_docs, service_name, client, waiter_model
)


def _assert_contains_lines_in_order(lines, contents):
for line in lines:
assert_true(line in contents)
assert line in contents
beginning = contents.find(line)
contents = contents[(beginning + len(line)):]

Expand Down
4 changes: 2 additions & 2 deletions tests/functional/dynamodb/test_stubber_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def test_table_query_can_be_stubbed_with_expressions(self):
response = table.query(KeyConditionExpression=key_expr,
FilterExpression=filter_expr)

self.assertEqual(list(), response['Items'])
assert response['Items'] == []
stubber.assert_no_pending_responses()

def test_table_scan_can_be_stubbed_with_expressions(self):
Expand All @@ -59,5 +59,5 @@ def test_table_scan_can_be_stubbed_with_expressions(self):
with stubber:
response = table.scan(FilterExpression=filter_expr)

self.assertEqual(list(), response['Items'])
assert response['Items'] == []
stubber.assert_no_pending_responses()
2 changes: 1 addition & 1 deletion tests/functional/dynamodb/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def setUp(self):

def test_resource_has_batch_writer_added(self):
table = self.resource.Table('mytable')
self.assertTrue(hasattr(table, 'batch_writer'))
assert hasattr(table, 'batch_writer')

def test_operation_without_output(self):
table = self.resource.Table('mytable')
Expand Down
5 changes: 2 additions & 3 deletions tests/functional/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ def setUp(self):
self.ec2_resource = self.session.resource('ec2')

def test_can_use_collection_methods(self):
self.assertIsInstance(
self.ec2_resource.instances.all(), ResourceCollection)
assert isinstance(self.ec2_resource.instances.all(), ResourceCollection)

def test_can_chain_methods(self):
self.assertIsInstance(
assert isinstance(
self.ec2_resource.instances.all().page_size(5), ResourceCollection)
26 changes: 12 additions & 14 deletions tests/functional/test_dynamodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,12 @@ def test_resource(self):
table.scan(FilterExpression=Attr('mykey').eq('myvalue'))
request = self.make_request_mock.call_args_list[0][0][1]
request_params = json.loads(request['body'].decode('utf-8'))
self.assertEqual(
request_params,
{'TableName': 'MyTable',
'FilterExpression': '#n0 = :v0',
'ExpressionAttributeNames': {'#n0': 'mykey'},
'ExpressionAttributeValues': {':v0': {'S': 'myvalue'}}}
)
assert request_params == {
'TableName': 'MyTable',
'FilterExpression': '#n0 = :v0',
'ExpressionAttributeNames': {'#n0': 'mykey'},
'ExpressionAttributeValues': {':v0': {'S': 'myvalue'}}
}

def test_client(self):
dynamodb = self.session.client('dynamodb')
Expand All @@ -62,10 +61,9 @@ def test_client(self):
)
request = self.make_request_mock.call_args_list[0][0][1]
request_params = json.loads(request['body'].decode('utf-8'))
self.assertEqual(
request_params,
{'TableName': 'MyTable',
'FilterExpression': '#n0 = :v0',
'ExpressionAttributeNames': {'#n0': 'mykey'},
'ExpressionAttributeValues': {':v0': {'S': 'myvalue'}}}
)
assert request_params == {
'TableName': 'MyTable',
'FilterExpression': '#n0 = :v0',
'ExpressionAttributeNames': {'#n0': 'mykey'},
'ExpressionAttributeValues': {':v0': {'S': 'myvalue'}}
}
Loading

0 comments on commit fb82bde

Please sign in to comment.