Skip to content

Commit

Permalink
feat(identifiers): Check Python Runtime
Browse files Browse the repository at this point in the history
Issues a WARNING if the Python Version will become unsupported.
Prints an ERROR to STDERR if Python Version is unsupported.
Will start issuing WARNING for Python Version less than 3.6.
Will start printing ERROR for Python Version less than 3.5 AFTER Jan 1st, 2022.
  • Loading branch information
texastony committed Nov 3, 2021
1 parent f1edc18 commit 634c588
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 2 deletions.
5 changes: 3 additions & 2 deletions src/aws_encryption_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@
# language governing permissions and limitations under the License.
"""High level AWS Encryption SDK client functions."""
# Below are imported for ease of use by implementors

import warnings

import attr

from aws_encryption_sdk.caches.local import LocalCryptoMaterialsCache # noqa
from aws_encryption_sdk.caches.null import NullCryptoMaterialsCache # noqa
from aws_encryption_sdk.exceptions import AWSEncryptionSDKClientError # noqa
from aws_encryption_sdk.identifiers import Algorithm, CommitmentPolicy, __version__ # noqa
from aws_encryption_sdk.identifiers import Algorithm, CommitmentPolicy, __version__, check_python_version # noqa
from aws_encryption_sdk.internal.utils.signature import SignaturePolicy # noqa
from aws_encryption_sdk.key_providers.kms import ( # noqa
DiscoveryAwsKmsMasterKeyProvider,
Expand All @@ -36,6 +35,8 @@
StreamEncryptor,
)

check_python_version()


@attr.s(hash=True)
class EncryptionSDKClientConfig(object):
Expand Down
44 changes: 44 additions & 0 deletions src/aws_encryption_sdk/identifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""AWS Encryption SDK native data structures for defining implementation-specific characteristics."""
import datetime
import struct
import sys
import warnings
from enum import Enum

from cryptography.hazmat.primitives import hashes
Expand Down Expand Up @@ -378,3 +381,44 @@ class CommitmentPolicy(Enum):
FORBID_ENCRYPT_ALLOW_DECRYPT = 0
REQUIRE_ENCRYPT_ALLOW_DECRYPT = 1
REQUIRE_ENCRYPT_REQUIRE_DECRYPT = 2


class PythonVersionSupport:
"""Configures Python Version warnings/error messaging"""

WARN_BELOW_MAJOR = 3
WARN_BELOW_MINOR = 6
ERROR_BELOW_MAJOR = 3
ERROR_BELOW_MINOR = 5
ERROR_DATE = datetime.datetime(year=2022, month=1, day=1)


def check_python_version(
warn_below_major=PythonVersionSupport.WARN_BELOW_MAJOR,
warn_below_minor=PythonVersionSupport.WARN_BELOW_MINOR,
error_below_major=PythonVersionSupport.ERROR_BELOW_MAJOR,
error_below_minor=PythonVersionSupport.ERROR_BELOW_MINOR,
error_date=PythonVersionSupport.ERROR_DATE,
):
"""Checks that we are on a supported version of Python.
Prints an error message to stderr if the Python Version is unsupported and therefore untested.
Emits a warning if the Python version will be unsupported.
"""
if datetime.datetime.now() > error_date and (
sys.version_info.major < error_below_major or sys.version_info.minor < error_below_minor
):
sys.stderr.write(
"ERROR: Python {} is not supported by the aws-encryption-sdk! ".format(
".".join(map(str, [sys.version_info.major, sys.version_info.minor]))
)
+ "Please upgrade to Python {} or higher.".format(".".join(map(str, [warn_below_major, warn_below_minor])))
)
return
if sys.version_info.major < warn_below_major or sys.version_info.minor < warn_below_minor:
warnings.warn(
"Python {} support will be removed in a future release. ".format(
".".join(map(str, [sys.version_info.major, sys.version_info.minor]))
)
+ "Please upgrade to Python {} or higher.".format(".".join(map(str, [warn_below_major, warn_below_minor]))),
DeprecationWarning,
)
62 changes: 62 additions & 0 deletions test/unit/test_check_python_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# 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.
"""Unit test suite for ensuring the Python Runtime is supported."""
import datetime
import sys

import mock
import pytest

from aws_encryption_sdk import check_python_version
from aws_encryption_sdk.identifiers import PythonVersionSupport

pytestmark = [pytest.mark.unit, pytest.mark.local]


class TestBeforeErrorDate:
def test_happy_version(self):
with mock.patch.object(sys, "version_info") as v_info:
v_info.major = PythonVersionSupport.WARN_BELOW_MAJOR
v_info.minor = PythonVersionSupport.WARN_BELOW_MINOR
with pytest.warns(None) as record:
check_python_version(error_date=datetime.datetime.now() + datetime.timedelta(days=1))
assert len(record) == 0

def test_below_warn(self):
with mock.patch.object(sys, "version_info") as v_info:
v_info.major = PythonVersionSupport.WARN_BELOW_MAJOR - 1
v_info.minor = PythonVersionSupport.WARN_BELOW_MINOR
with pytest.warns(DeprecationWarning):
check_python_version(error_date=datetime.datetime.now() + datetime.timedelta(days=1))


class TestAfterErrorDate:
def test_happy_version(self, capsys):
with mock.patch.object(sys, "version_info") as v_info:
v_info.major = PythonVersionSupport.WARN_BELOW_MAJOR
v_info.minor = PythonVersionSupport.WARN_BELOW_MINOR
with pytest.warns(None) as record:
check_python_version(error_date=datetime.datetime.now() - datetime.timedelta(days=1))
assert len(record) == 0
captured = capsys.readouterr().err
assert "ERROR" not in captured

def test_below_error(self, capsys):
with mock.patch.object(sys, "version_info") as v_info:
v_info.major = PythonVersionSupport.ERROR_BELOW_MAJOR
v_info.minor = PythonVersionSupport.ERROR_BELOW_MINOR - 1
with pytest.warns(None) as record:
check_python_version(error_date=datetime.datetime.now() - datetime.timedelta(days=1))
assert len(record) == 0
captured = capsys.readouterr().err
assert "ERROR" in captured

0 comments on commit 634c588

Please sign in to comment.