diff --git a/.changes/1.29.0.json b/.changes/1.29.0.json new file mode 100644 index 000000000..33afbbe29 --- /dev/null +++ b/.changes/1.29.0.json @@ -0,0 +1,15 @@ +{ + "schema-version": "1.0", + "changes": [ + { + "type": "feature", + "category": "Python", + "description": "Add support for Python 3.10 (#2037)" + }, + { + "type": "enhancement", + "category": "Pip", + "description": "Bump pip version range to latest version <23.2 (#2034)" + } + ] +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6331c3613..354f35af2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,4 +9,3 @@ updates: allow: - dependency-name: pip - dependency-name: click - - dependency-name: attrs diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index d32176954..c7aad1b21 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - python-version: [3.8, 3.9] + python-version: [3.8, 3.9, '3.10', 3.11] steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 @@ -53,7 +53,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7, 3.8, 3.9] + python-version: [3.7, 3.8, 3.9, '3.10', 3.11] cdk-version: [cdk, cdkv2] steps: - uses: actions/checkout@v2 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7d2aefe6c..60cc2cece 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,13 @@ CHANGELOG ========= +1.29.0 +====== + +* feature:Python:Add support for Python 3.10 (#2037) +* enhancement:Pip:Bump pip version range to latest version <23.2 (#2034) + + 1.28.0 ====== diff --git a/README.rst b/README.rst index 7e23adcd9..9e043c3a2 100644 --- a/README.rst +++ b/README.rst @@ -111,7 +111,7 @@ Quickstart In this tutorial, you'll use the ``chalice`` command line utility to create and deploy a basic REST API. This quickstart uses Python 3.7, but AWS Chalice supports all versions of python supported by AWS Lambda, -which includes python3.6, python3.7, python3.8, python3.9. +which includes python3.6, python3.7, python3.8, python3.9, python3.10, python3.11. You can find the latest versions of python on the `Python download page `_. diff --git a/chalice/app.py b/chalice/app.py index 06753fad2..921534510 100644 --- a/chalice/app.py +++ b/chalice/app.py @@ -22,7 +22,7 @@ from collections.abc import MutableMapping -__version__: str = '1.28.0' +__version__: str = '1.29.0' from typing import List, Dict, Any, Optional, Sequence, Union, Callable, Set, \ Iterator, TYPE_CHECKING, Tuple diff --git a/chalice/config.py b/chalice/config.py index 178c91ffb..9b73a682a 100644 --- a/chalice/config.py +++ b/chalice/config.py @@ -151,14 +151,13 @@ def lambda_python_version(self) -> str: if major == 2: return 'python2.7' # Python 3 for backwards compatibility needs to select python3.6 - # for python versions 3.0-3.6. 3.7 and higher will use python3.7. + # for python versions 3.0-3.6. 3.7-3.10 will use their version. + # 3.11 and higher will use 3.11 elif (major, minor) <= (3, 6): return 'python3.6' - elif (major, minor) <= (3, 7): - return 'python3.7' - elif (major, minor) <= (3, 8): - return 'python3.8' - return 'python3.9' + elif (major, minor) <= (3, 10): + return 'python%s.%s' % (major, minor) + return 'python3.11' @property def log_retention_in_days(self) -> int: diff --git a/chalice/deploy/packager.py b/chalice/deploy/packager.py index dd8e27629..813e57d34 100644 --- a/chalice/deploy/packager.py +++ b/chalice/deploy/packager.py @@ -81,6 +81,8 @@ class BaseLambdaDeploymentPackager(object): 'python3.7': 'cp37m', 'python3.8': 'cp38', 'python3.9': 'cp39', + 'python3.10': 'cp310', + 'python3.11': 'cp311', } def __init__( @@ -497,6 +499,8 @@ class DependencyBuilder(object): 'cp36m': (2, 17), 'cp37m': (2, 17), 'cp38': (2, 26), + 'cp310': (2, 26), + 'cp311': (2, 26), } # Fallback version if we're on an unknown python version # not in _RUNTIME_GLIBC. diff --git a/docs/source/conf.py b/docs/source/conf.py index b72d58762..aa558efbc 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -61,9 +61,9 @@ # built documents. # # The short X.Y version. -version = u'1.28' +version = u'1.29' # The full version, including alpha/beta/rc tags. -release = u'1.28.0' +release = u'1.29.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/topics/middleware.rst b/docs/source/topics/middleware.rst index 90a8ea0de..465315bc1 100644 --- a/docs/source/topics/middleware.rst +++ b/docs/source/topics/middleware.rst @@ -271,15 +271,15 @@ Integrating with AWS Lambda Powertools -------------------------------------- `AWS Lambda Powertools -`__ is a suite of +`__ is a suite of utilities for AWS Lambda functions that makes tracing with AWS X-Ray, structured logging and creating custom metrics asynchronously easier. You can use Chalice middleware to easily integrate Lambda Powertools with your Chalice apps. In this example, we'll use the `Logger -`__ -and `Tracer `__ +`__ +and `Tracer `__ and convert them to Chalice middleware so they will be automatically applied to all Lambda functions in our application. diff --git a/setup.py b/setup.py index 586081168..cf0058849 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ def recursive_include(relative_dir): 'typing==3.6.4;python_version<"3.7"', 'typing-extensions>=4.0.0,<5.0.0', 'six>=1.10.0,<2.0.0', - 'pip>=9,<23.1', + 'pip>=9,<23.2', 'jmespath>=0.9.3,<2.0.0', 'pyyaml>=5.3.1,<7.0.0', 'inquirer>=2.7.0,<3.0.0', @@ -35,7 +35,7 @@ def recursive_include(relative_dir): setup( name='chalice', - version='1.28.0', + version='1.29.0', description="Microframework", long_description=README, author="James Saryerwinnie", @@ -44,7 +44,7 @@ def recursive_include(relative_dir): packages=find_packages(exclude=['tests', 'tests.*']), install_requires=install_requires, extras_require={ - 'event-file-poller': ['watchdog==0.9.0'], + 'event-file-poller': ['watchdog==2.3.1'], 'cdk': [ 'aws_cdk.aws_iam>=1.85.0,<2.0', 'aws_cdk.aws-s3-assets>=1.85.0,<2.0', @@ -74,5 +74,7 @@ def recursive_include(relative_dir): 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', ], ) diff --git a/tests/functional/cli/test_cli.py b/tests/functional/cli/test_cli.py index 325dc5421..e6672fd61 100644 --- a/tests/functional/cli/test_cli.py +++ b/tests/functional/cli/test_cli.py @@ -415,6 +415,10 @@ def test_error_when_no_deployed_record(runner, mock_cli_factory): reason="Cannot generate pipeline for python3.8.") @pytest.mark.skipif(sys.version_info[:2] == (3, 9), reason="Cannot generate pipeline for python3.9.") +@pytest.mark.skipif(sys.version_info[:2] == (3, 10), + reason="Cannot generate pipeline for python3.10.") +@pytest.mark.skipif(sys.version_info[:2] == (3, 11), + reason="Cannot generate pipeline for python3.11.") def test_can_generate_pipeline_for_all(runner): with runner.isolated_filesystem(): newproj.create_new_project_skeleton('testproject') diff --git a/tests/integration/test_package.py b/tests/integration/test_package.py index e18438f0c..69db7ac51 100644 --- a/tests/integration/test_package.py +++ b/tests/integration/test_package.py @@ -16,10 +16,95 @@ from chalice.deploy.packager import NoSuchPackageError +PY_VERSION = sys.version_info[:2] +VERSION_CUTOFF = (3, 9) +# We're being cautious here, but we want to fix the package versions we +# try to install on older versions of python. +# If the python version being tested is less than the VERSION_CUTOFF of 3.9, +# then we'll install the `legacy_version` in the packages below. This is to +# ensure we don't regress on being able to package older package versions on +# older versions on python. Any python version above the VERSION_CUTOFF will +# install the `version` identifier. That way newer versions of python won't +# need to update this list as long as a package can still be installed on +# 3.10 or higher. +PACKAGES_TO_TEST = { + 'pandas': { + 'version': '1.5.3', + 'legacy_version': '1.1.5', + 'contents': [ + 'pandas/_libs/__init__.py', + 'pandas/io/sas/_sas.cpython-*-x86_64-linux-gnu.so' + ], + }, + 'SQLAlchemy': { + 'version': '1.4.47', + 'legacy_version': '1.3.20', + 'contents': [ + 'sqlalchemy/__init__.py', + 'sqlalchemy/cresultproxy.cpython-*-x86_64-linux-gnu.so' + ], + }, + 'numpy': { + 'version': '1.23.3', + 'legacy_version': '1.19.4', + 'contents': [ + 'numpy/__init__.py', + 'numpy/core/_struct_ufunc_tests.cpython-*-x86_64-linux-gnu.so' + ], + }, + 'cryptography': { + 'version': '3.3.1', + 'legacy_version': '3.3.1', + 'contents': [ + 'cryptography/__init__.py', + 'cryptography/hazmat/bindings/_openssl.abi3.so' + ], + }, + 'Jinja2': { + 'version': '2.11.2', + 'legacy_version': '2.11.2', + 'contents': ['jinja2/__init__.py'], + }, + 'Mako': { + 'version': '1.1.3', + 'legacy_version': '1.1.3', + 'contents': ['mako/__init__.py'], + }, + 'MarkupSafe': { + 'version': '1.1.1', + 'legacy_version': '1.1.1', + 'contents': ['markupsafe/__init__.py'], + }, + 'scipy': { + 'version': '1.10.1', + 'legacy_version': '1.5.4', + 'contents': [ + 'scipy/__init__.py', + 'scipy/cluster/_hierarchy.cpython-*-x86_64-linux-gnu.so' + ], + }, + 'cffi': { + 'version': '1.15.1', + 'legacy_version': '1.14.5', + 'contents': ['_cffi_backend.cpython-*-x86_64-linux-gnu.so'], + }, + 'pygit2': { + 'version': '1.10.1', + 'legacy_version': '1.5.0', + 'contents': ['pygit2/_pygit2.cpython-*-x86_64-linux-gnu.so'], + }, + 'pyrsistent': { + 'version': '0.17.3', + 'legacy_version': '0.17.3', + 'contents': ['pyrsistent/__init__.py'], + }, +} + + @contextmanager def cd(path): + original_dir = os.getcwd() try: - original_dir = os.getcwd() os.chdir(path) yield finally: @@ -43,41 +128,26 @@ def _get_random_package_name(): return 'foobar-%s' % str(uuid.uuid4())[:8] +def _get_package_install_test_cases(): + testcases = [] + if PY_VERSION <= VERSION_CUTOFF: + version_key = 'legacy_version' + else: + version_key = 'version' + for package, config in PACKAGES_TO_TEST.items(): + package_version = f'{package}=={config[version_key]}' + testcases.append( + (package_version, config['contents']) + ) + return testcases + + # This test can take a while, but you can set this env var to make sure that # the commonly used python packages can be packaged successfully. @pytest.mark.skipif(not os.environ.get('CHALICE_TEST_EXTENDED_PACKAGING'), reason='Set CHALICE_TEST_EXTENDED_PACKAGING for extended ' 'packaging tests.') -@pytest.mark.skipif(sys.version_info[0] == 2, - reason='Extended packaging tests only run on py3.') -@pytest.mark.parametrize( - 'package,contents', [ - ('pandas==1.1.5', [ - 'pandas/_libs/__init__.py', - 'pandas/io/sas/_sas.cpython-*-x86_64-linux-gnu.so']), - ('SQLAlchemy==1.3.20', [ - 'sqlalchemy/__init__.py', - 'sqlalchemy/cresultproxy.cpython-*-x86_64-linux-gnu.so']), - ('numpy==1.19.4', [ - 'numpy/__init__.py', - 'numpy/core/_struct_ufunc_tests.cpython-*-x86_64-linux-gnu.so']), - ('cryptography==3.3.1', [ - 'cryptography/__init__.py', - 'cryptography/hazmat/bindings/_openssl.abi3.so']), - ('Jinja2==2.11.2', ['jinja2/__init__.py']), - ('Mako==1.1.3', ['mako/__init__.py']), - ('MarkupSafe==1.1.1', ['markupsafe/__init__.py']), - ('scipy==1.5.4', [ - 'scipy/__init__.py', - 'scipy/cluster/_hierarchy.cpython-*-x86_64-linux-gnu.so']), - ('cffi==1.14.5', [ - '_cffi_backend.cpython-*-x86_64-linux-gnu.so']), - ('pygit2==1.5.0', [ - 'pygit2/_pygit2.cpython-*-x86_64-linux-gnu.so']), - ('pyrsistent==0.17.3', [ - 'pyrsistent/__init__.py']), - ] -) +@pytest.mark.parametrize('package,contents', _get_package_install_test_cases()) def test_package_install_smoke_tests(package, contents, runner, app_skeleton): assert_can_package_dependency(runner, app_skeleton, package, contents) @@ -144,10 +214,11 @@ def test_can_package_sqlalchemy(self, runner, app_skeleton, @pytest.mark.skipif(sys.version_info[0] == 2, reason='pandas==1.1.5 is only suported on py3.') def test_can_package_pandas(self, runner, app_skeleton, no_local_config): + version = '1.5.3' if sys.version_info[1] >= 10 else '1.1.5' assert_can_package_dependency( runner, app_skeleton, - 'pandas==1.1.5', + 'pandas==' + version, contents=[ 'pandas/_libs/__init__.py', ], diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index 38b748429..c386fbe0f 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -375,8 +375,12 @@ def test_can_load_python_version(): expected_runtime = 'python3.7' elif minor <= 8: expected_runtime = 'python3.8' - else: + elif minor <= 9: expected_runtime = 'python3.9' + elif minor <= 10: + expected_runtime = 'python3.10' + else: + expected_runtime = 'python3.11' assert c.lambda_python_version == expected_runtime