From 913e3104a1b56af9f250aad1e389aa335ad34deb Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Sun, 16 Aug 2020 23:02:11 +0300 Subject: [PATCH 01/14] feat: RFC: Validate incoming and outgoing events utility #95 --- README.md | 1 + aws_lambda_powertools/validation/__init__.py | 2 + aws_lambda_powertools/validation/schemas.py | 56 ++++++ aws_lambda_powertools/validation/validator.py | 126 +++++++++++++ poetry.lock | 58 +++++- pyproject.toml | 2 + tests/functional/test_validator.py | 171 ++++++++++++++++++ 7 files changed, 415 insertions(+), 1 deletion(-) create mode 100644 aws_lambda_powertools/validation/__init__.py create mode 100644 aws_lambda_powertools/validation/schemas.py create mode 100644 aws_lambda_powertools/validation/validator.py create mode 100644 tests/functional/test_validator.py diff --git a/README.md b/README.md index 68090913dbe..1d9f04aec99 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ A suite of utilities for AWS Lambda Functions that makes tracing with AWS X-Ray, * **[Metrics](https://awslabs.github.io/aws-lambda-powertools-python/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) * **[Bring your own middleware](https://awslabs.github.io/aws-lambda-powertools-python/utilities/middleware_factory/)** - Decorator factory to create your own middleware to run logic before, and after each Lambda invocation * **[Parameters utility](https://awslabs.github.io/aws-lambda-powertools-python/utilities/parameters/)** - Retrieve and cache parameter values from Parameter Store, Secrets Manager, or DynamoDB +* **[Validation](https://)** - ### Installation diff --git a/aws_lambda_powertools/validation/__init__.py b/aws_lambda_powertools/validation/__init__.py new file mode 100644 index 00000000000..924f64e70cc --- /dev/null +++ b/aws_lambda_powertools/validation/__init__.py @@ -0,0 +1,2 @@ +"""Validation utility +""" diff --git a/aws_lambda_powertools/validation/schemas.py b/aws_lambda_powertools/validation/schemas.py new file mode 100644 index 00000000000..bcdf082eeb3 --- /dev/null +++ b/aws_lambda_powertools/validation/schemas.py @@ -0,0 +1,56 @@ +from datetime import date, datetime +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, root_validator +from typing_extensions import Literal + + +class DynamoScheme(BaseModel): + ApproximateCreationDateTime: date + Keys: Dict[Literal["id"], Dict[Literal["S"], str]] + NewImage: Optional[Dict[str, Any]] = {} + OldImage: Optional[Dict[str, Any]] = {} + SequenceNumber: str + SizeBytes: int + StreamViewType: Literal["NEW_AND_OLD_IMAGES", "KEYS_ONLY", "NEW_IMAGE", "OLD_IMAGE"] + + @root_validator + def check_one_image_exists(cls, values): + newimg, oldimg = values.get("NewImage"), values.get("OldImage") + stream_type = values.get("StreamViewType") + if stream_type == "NEW_AND_OLD_IMAGES" and not newimg and not oldimg: + raise TypeError("DynamoDB streams schema failed validation, missing both new & old stream images") + return values + + +class DynamoRecordSchema(BaseModel): + eventID: str + eventName: Literal["INSERT", "MODIFY", "REMOVE"] + eventVersion: float + eventSource: Literal["aws:dynamodb"] + awsRegion: str + eventSourceARN: str + dynamodb: DynamoScheme + + +class DynamoDBSchema(BaseModel): + Records: List[DynamoRecordSchema] + + +class EventBridgeSchema(BaseModel): + version: str + id: str # noqa: A003,VNE003 + source: str + account: int + time: datetime + region: str + resources: List[str] + detail: Dict[str, Any] + + +class SqsSchema(BaseModel): + todo: str + + +class SnsSchema(BaseModel): + todo: str diff --git a/aws_lambda_powertools/validation/validator.py b/aws_lambda_powertools/validation/validator.py new file mode 100644 index 00000000000..b3ff685007b --- /dev/null +++ b/aws_lambda_powertools/validation/validator.py @@ -0,0 +1,126 @@ +import logging +from abc import ABC, abstractmethod +from typing import Any, Callable, Dict + +from pydantic import BaseModel, ValidationError + +from aws_lambda_powertools.middleware_factory import lambda_handler_decorator +from aws_lambda_powertools.validation.schemas import DynamoDBSchema, EventBridgeSchema + +logger = logging.getLogger(__name__) + + +class Envelope(ABC): + def _parse_user_dict_schema(self, user_event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + logger.debug("parsing user dictionary schema") + try: + return inbound_schema_model(**user_event) + except (ValidationError, TypeError): + logger.exception("Valdation exception while extracting user custom schema") + raise + + def _parse_user_json_string_schema(self, user_event: str, inbound_schema_model: BaseModel) -> Any: + logger.debug("parsing user dictionary schema") + try: + return inbound_schema_model.parse_raw(user_event) + except (ValidationError, TypeError): + logger.exception("Valdation exception while extracting user custom schema") + raise + + @abstractmethod + def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + return NotImplemented + + +class UserEnvelope(Envelope): + def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + try: + return inbound_schema_model(**event) + except (ValidationError, TypeError): + logger.exception("Valdation exception received from input user custom envelope event") + raise + + +class EventBridgeEnvelope(Envelope): + def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + try: + parsed_envelope = EventBridgeSchema(**event) + except (ValidationError, TypeError): + logger.exception("Valdation exception received from input eventbridge event") + raise + return self._parse_user_dict_schema(parsed_envelope.detail, inbound_schema_model) + + +class DynamoDBEnvelope(Envelope): + def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + try: + parsed_envelope = DynamoDBSchema(**event) + except (ValidationError, TypeError): + logger.exception("Valdation exception received from input dynamodb stream event") + raise + output = [] + for record in parsed_envelope.Records: + parsed_new_image = ( + {} + if not record.dynamodb.NewImage + else self._parse_user_dict_schema(record.dynamodb.NewImage, inbound_schema_model) + ) # noqa: E501 + parsed_old_image = ( + {} + if not record.dynamodb.OldImage + else self._parse_user_dict_schema(record.dynamodb.OldImage, inbound_schema_model) + ) # noqa: E501 + output.append({"new": parsed_new_image, "old": parsed_old_image}) + return output + + +@lambda_handler_decorator +def validator( + handler: Callable[[Dict, Any], Any], + event: Dict[str, Any], + context: Dict[str, Any], + inbound_schema_model: BaseModel, + outbound_schema_model: BaseModel, + envelope: Envelope, +) -> Any: + """Decorator to create validation for lambda handlers events - both inbound and outbound + + As Lambda follows (event, context) signature we can remove some of the boilerplate + and also capture any exception any Lambda function throws or its response as metadata + + Example + ------- + **Lambda function using validation decorator** + + @validator(inbound=inbound_schema_model, outbound=outbound_schema_model) + def handler(parsed_event_model, context): + ... + + Parameters + ---------- + todo add + + Raises + ------ + err + TypeError or pydantic.ValidationError or any exception raised by the lambda handler itself + """ + lambda_handler_name = handler.__name__ + logger.debug("Validating inbound schema") + parsed_event_model = envelope.parse(event, inbound_schema_model) + try: + logger.debug(f"Calling handler {lambda_handler_name}") + response = handler({"orig": event, "custom": parsed_event_model}, context) + logger.debug("Received lambda handler response successfully") + logger.debug(response) + except Exception: + logger.exception(f"Exception received from {lambda_handler_name}") + raise + + try: + logger.debug("Validating outbound response schema") + outbound_schema_model(**response) + except (ValidationError, TypeError): + logger.exception(f"Validation exception received from {lambda_handler_name} response event") + raise + return response diff --git a/poetry.lock b/poetry.lock index e7b7cdff1db..bcd22e5f2d5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -112,6 +112,17 @@ dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.int docs = ["sphinx", "zope.interface"] tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +[[package]] +category = "dev" +description = "AWS Lambda Context class for type checking and testing" +name = "aws-lambda-context" +optional = false +python-versions = ">= 3.6" +version = "1.1.0" + +[package.extras] +tests = ["flake8 (3.7.8)", "isort (4.3.21)", "mypy (0.720)", "black (19.3b0)", "pytest (5.0.1)", "pytest-cov (2.7.1)", "pre-commit (1.17.0)", "bump2version (0.5.10)"] + [[package]] category = "main" description = "The AWS X-Ray SDK for Python (the SDK) enables Python developers to record and emit information from within their applications to the AWS X-Ray service." @@ -671,6 +682,24 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.6.0" +[[package]] +category = "main" +description = "Data validation and settings management using python 3.6 type hinting" +name = "pydantic" +optional = false +python-versions = ">=3.6" +version = "1.6.1" + +[package.dependencies] +[package.dependencies.dataclasses] +python = "<3.7" +version = ">=0.6" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] +typing_extensions = ["typing-extensions (>=3.7.2)"] + [[package]] category = "dev" description = "passive checker of Python programs" @@ -948,6 +977,10 @@ version = "1.4.2" idna = ">=2.0" multidict = ">=4.0" +[package.dependencies.typing-extensions] +python = "<3.8" +version = ">=3.7.4" + [[package]] category = "main" description = "Backport of pathlib-compatible object wrapper for zip files" @@ -1008,6 +1041,10 @@ attrs = [ {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, ] +aws-lambda-context = [ + {file = "aws-lambda-context-1.1.0.tar.gz", hash = "sha256:b6a6d3360671b25bb171335c7e6510b22e60c6fd5db99803f478c986d3230220"}, + {file = "aws_lambda_context-1.1.0-py3-none-any.whl", hash = "sha256:d03b16aaf8abac30b71bc5d66ed8edadd8805e0d581f73f1e9b4b171635c817d"}, +] aws-xray-sdk = [ {file = "aws-xray-sdk-2.6.0.tar.gz", hash = "sha256:abf5b90f740e1f402e23414c9670e59cb9772e235e271fef2bce62b9100cbc77"}, {file = "aws_xray_sdk-2.6.0-py2.py3-none-any.whl", hash = "sha256:076f7c610cd3564bbba3507d43e328fb6ff4a2e841d3590f39b2c3ce99d41e1d"}, @@ -1272,6 +1309,25 @@ pycodestyle = [ {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, ] +pydantic = [ + {file = "pydantic-1.6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:418b84654b60e44c0cdd5384294b0e4bc1ebf42d6e873819424f3b78b8690614"}, + {file = "pydantic-1.6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4900b8820b687c9a3ed753684337979574df20e6ebe4227381d04b3c3c628f99"}, + {file = "pydantic-1.6.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b49c86aecde15cde33835d5d6360e55f5e0067bb7143a8303bf03b872935c75b"}, + {file = "pydantic-1.6.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2de562a456c4ecdc80cf1a8c3e70c666625f7d02d89a6174ecf63754c734592e"}, + {file = "pydantic-1.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f769141ab0abfadf3305d4fcf36660e5cf568a666dd3efab7c3d4782f70946b1"}, + {file = "pydantic-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2dc946b07cf24bee4737ced0ae77e2ea6bc97489ba5a035b603bd1b40ad81f7e"}, + {file = "pydantic-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:36dbf6f1be212ab37b5fda07667461a9219c956181aa5570a00edfb0acdfe4a1"}, + {file = "pydantic-1.6.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:1783c1d927f9e1366e0e0609ae324039b2479a1a282a98ed6a6836c9ed02002c"}, + {file = "pydantic-1.6.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:cf3933c98cb5e808b62fae509f74f209730b180b1e3c3954ee3f7949e083a7df"}, + {file = "pydantic-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f8af9b840a9074e08c0e6dc93101de84ba95df89b267bf7151d74c553d66833b"}, + {file = "pydantic-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:40d765fa2d31d5be8e29c1794657ad46f5ee583a565c83cea56630d3ae5878b9"}, + {file = "pydantic-1.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3fa799f3cfff3e5f536cbd389368fc96a44bb30308f258c94ee76b73bd60531d"}, + {file = "pydantic-1.6.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:6c3f162ba175678218629f446a947e3356415b6b09122dcb364e58c442c645a7"}, + {file = "pydantic-1.6.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:eb75dc1809875d5738df14b6566ccf9fd9c0bcde4f36b72870f318f16b9f5c20"}, + {file = "pydantic-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:530d7222a2786a97bc59ee0e0ebbe23728f82974b1f1ad9a11cd966143410633"}, + {file = "pydantic-1.6.1-py36.py37.py38-none-any.whl", hash = "sha256:b5b3489cb303d0f41ad4a7390cf606a5f2c7a94dcba20c051cd1c653694cb14d"}, + {file = "pydantic-1.6.1.tar.gz", hash = "sha256:54122a8ed6b75fe1dd80797f8251ad2063ea348a03b77218d73ea9fe19bd4e73"}, +] pyflakes = [ {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, @@ -1432,4 +1488,4 @@ yarl = [ zipp = [ {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, -] +] \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 0cfd9c45bed..1f4bee17c59 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ python = "^3.6" aws-xray-sdk = "^2.5.0" fastjsonschema = "~=2.14.4" boto3 = "^1.12" +pydantic = "^1.6.1" [tool.poetry.dev-dependencies] coverage = {extras = ["toml"], version = "^5.0.3"} @@ -48,6 +49,7 @@ xenon = "^0.7.0" flake8-eradicate = "^0.3.0" dataclasses = {version = "*", python = "~3.6"} flake8-bugbear = "^20.1.4" +aws_lambda_context = "^1.1.0" [tool.coverage.run] source = ["aws_lambda_powertools"] diff --git a/tests/functional/test_validator.py b/tests/functional/test_validator.py new file mode 100644 index 00000000000..afbdb5242eb --- /dev/null +++ b/tests/functional/test_validator.py @@ -0,0 +1,171 @@ +import io +from http import HTTPStatus +from typing import Any, Dict, Optional + +import pytest +from aws_lambda_context import LambdaContext +from pydantic import BaseModel +from pydantic.error_wrappers import ValidationError + +from aws_lambda_powertools.validation.validator import DynamoDBEnvelope, EventBridgeEnvelope, UserEnvelope, validator + + +class OutboundSchema(BaseModel): + response_code: HTTPStatus + message: str + + +class InboundSchema(BaseModel): + greeting: str + + +@pytest.fixture +def stdout(): + return io.StringIO() + + +@validator(inbound_schema_model=InboundSchema, outbound_schema_model=OutboundSchema, envelope=UserEnvelope()) +def my_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: + assert event["custom"] + assert event["orig"] + return {"response_code": 200, "message": "working"} + + +@validator(inbound_schema_model=InboundSchema, outbound_schema_model=OutboundSchema, envelope=UserEnvelope()) +def my_outbound_fail_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: + assert event["custom"] + assert event["orig"] + return {"stuff": 200, "message": "working"} + + +def test_ok_inbound_outbound_validation(): + my_handler({"greeting": "hello"}, LambdaContext()) + + +def test_fail_outbound(): + with pytest.raises(ValidationError): + my_outbound_fail_handler({"greeting": "hello"}, LambdaContext()) + + +def test_fail_inbound_validation(): + with pytest.raises(ValidationError): + my_handler({"this_fails": "hello"}, LambdaContext()) + + +class MyMessage(BaseModel): + message: str + messageId: int + + +@validator(inbound_schema_model=MyMessage, outbound_schema_model=OutboundSchema, envelope=DynamoDBEnvelope()) +def dynamodb_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: + assert event["custom"] + # first record + assert not event["custom"][0]["old"] + assert event["custom"][0]["new"].message == "hello" + assert event["custom"][0]["new"].messageId == 8 + # second record + assert event["custom"][1]["new"].message == "new_hello" + assert event["custom"][1]["new"].messageId == 88 + assert event["custom"][1]["old"].message == "hello" + assert event["custom"][1]["old"].messageId == 81 + # third record + assert not event["custom"][2]["new"] + assert event["custom"][2]["old"].message == "hello1" + assert event["custom"][2]["old"].messageId == 82 + assert event["orig"] + + return {"response_code": 200, "message": "working"} + + +def test_dynamodb_fail_inbound_validation(): + event = {"greeting": "hello"} + with pytest.raises(ValidationError): + dynamodb_handler(event, LambdaContext()) + + +def test_dynamodb_ok_inbound_outbound_validation(): + event = { + "Records": [ + { + "eventID": "8ae66d82798e8c34ca4a568d6d2ddb75", + "eventName": "INSERT", + "eventVersion": "1.1", + "eventSource": "aws:dynamodb", + "awsRegion": "eu-west-1", + "dynamodb": { + "ApproximateCreationDateTime": 1583747504.0, + "Keys": {"id": {"S": "a5890cc9-47c7-4667-928b-f072b93f7acd"}}, + "NewImage": {"message": "hello", "messageId": 8}, + "SequenceNumber": "4722000000000004992628049", + "SizeBytes": 215, + "StreamViewType": "NEW_AND_OLD_IMAGES", + }, + "eventSourceARN": "arn:aws:dynamodb/stream/2020-0", + }, + { + "eventID": "8ae66d82798e83333568d6d2ddb75", + "eventName": "MODIFY", + "eventVersion": "1.1", + "eventSource": "aws:dynamodb", + "awsRegion": "eu-west-1", + "dynamodb": { + "ApproximateCreationDateTime": 1583747504.0, + "Keys": {"id": {"S": "a5890cc9-47c7-4667-928b-f072b93f7acd"}}, + "NewImage": {"message": "new_hello", "messageId": 88}, + "OldImage": {"message": "hello", "messageId": 81}, + "SequenceNumber": "4722000000000004992628049", + "SizeBytes": 215, + "StreamViewType": "NEW_AND_OLD_IMAGES", + }, + "eventSourceARN": "arn:aws:dynamodb/stream/2020-0", + }, + { + "eventID": "8ae66d82798e8c34ca4a568d6d2ddb75", + "eventName": "REMOVE", + "eventVersion": "1.1", + "eventSource": "aws:dynamodb", + "awsRegion": "eu-west-1", + "dynamodb": { + "ApproximateCreationDateTime": 1583747504.0, + "Keys": {"id": {"S": "a5890cc9-47c7-4667-928b-f072b93f7acd"}}, + "OldImage": {"message": "hello1", "messageId": 82}, + "SequenceNumber": "4722000000000004992628049", + "SizeBytes": 215, + "StreamViewType": "NEW_AND_OLD_IMAGES", + }, + "eventSourceARN": "arn:aws:dynamodb/stream/2020-0", + }, + ] + } + dynamodb_handler(event, LambdaContext()) + + +@validator(inbound_schema_model=MyMessage, outbound_schema_model=OutboundSchema, envelope=EventBridgeEnvelope()) +def eventbridge_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: + assert event["custom"] + assert event["custom"].messageId == 8 + assert event["custom"].message == "hello" + assert event["orig"] + return {"response_code": 200, "message": "working"} + + +def test_eventbridge_ok_validation(): + event = { + "version": "0", + "id": "553961c5-5017-5763-6f21-f88d5f5f4b05", + "detail-type": "my func stream event json", + "source": "arn:aws:lambda:eu-west-1:88888888:function:my_func", + "account": "88888888", + "time": "2020-02-11T08:18:09Z", + "region": "eu-west-1", + "resources": ["arn:aws:dynamodb:eu-west-1:88888888:table/stream/2020-02"], + "detail": {"message": "hello", "messageId": 8}, + } + eventbridge_handler(event, LambdaContext()) + + +def test_eventbridge_fail_inbound_validation(): + event = {"greeting": "hello"} + with pytest.raises(ValidationError): + eventbridge_handler(event, LambdaContext()) From d50e26136676f5fb53879e8ea141458a2df3dd37 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Wed, 26 Aug 2020 18:00:17 +0200 Subject: [PATCH 02/14] improv: refactor structure to fit with utilities --- .../utilities/validation/__init__.py | 6 + .../validation/envelopes/__init__.py | 9 ++ .../utilities/validation/envelopes/base.py | 38 ++++++ .../validation/envelopes/dynamodb.py | 32 +++++ .../validation/envelopes/event_bridge.py | 19 +++ .../utilities/validation/schemas/__init__.py | 11 ++ .../validation/schemas/dynamodb.py} | 21 +-- .../validation/schemas/event_bridge.py | 15 +++ .../utilities/validation/schemas/sns.py | 5 + .../utilities/validation/schemas/sqs.py | 5 + .../utilities/validation/validator.py | 62 +++++++++ aws_lambda_powertools/validation/__init__.py | 2 - aws_lambda_powertools/validation/validator.py | 126 ------------------ tests/functional/test_validator.py | 2 +- 14 files changed, 204 insertions(+), 149 deletions(-) create mode 100644 aws_lambda_powertools/utilities/validation/__init__.py create mode 100644 aws_lambda_powertools/utilities/validation/envelopes/__init__.py create mode 100644 aws_lambda_powertools/utilities/validation/envelopes/base.py create mode 100644 aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py create mode 100644 aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py create mode 100644 aws_lambda_powertools/utilities/validation/schemas/__init__.py rename aws_lambda_powertools/{validation/schemas.py => utilities/validation/schemas/dynamodb.py} (78%) create mode 100644 aws_lambda_powertools/utilities/validation/schemas/event_bridge.py create mode 100644 aws_lambda_powertools/utilities/validation/schemas/sns.py create mode 100644 aws_lambda_powertools/utilities/validation/schemas/sqs.py create mode 100644 aws_lambda_powertools/utilities/validation/validator.py delete mode 100644 aws_lambda_powertools/validation/__init__.py delete mode 100644 aws_lambda_powertools/validation/validator.py diff --git a/aws_lambda_powertools/utilities/validation/__init__.py b/aws_lambda_powertools/utilities/validation/__init__.py new file mode 100644 index 00000000000..bc47c78b0ac --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/__init__.py @@ -0,0 +1,6 @@ +"""Validation utility +""" +from .envelopes import DynamoDBEnvelope, EventBridgeEnvelope, UserEnvelope +from .validator import validator + +__all__ = ["UserEnvelope", "DynamoDBEnvelope", "EventBridgeEnvelope", "validator"] diff --git a/aws_lambda_powertools/utilities/validation/envelopes/__init__.py b/aws_lambda_powertools/utilities/validation/envelopes/__init__.py new file mode 100644 index 00000000000..31d424a3b99 --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/envelopes/__init__.py @@ -0,0 +1,9 @@ +from .base import UserEnvelope +from .dynamodb import DynamoDBEnvelope +from .event_bridge import EventBridgeEnvelope + +__all__ = [ + "UserEnvelope", + "DynamoDBEnvelope", + "EventBridgeEnvelope", +] diff --git a/aws_lambda_powertools/utilities/validation/envelopes/base.py b/aws_lambda_powertools/utilities/validation/envelopes/base.py new file mode 100644 index 00000000000..d40bfaa0884 --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/envelopes/base.py @@ -0,0 +1,38 @@ +import logging +from abc import ABC, abstractmethod +from typing import Any, Dict + +from pydantic import BaseModel, ValidationError + +logger = logging.getLogger(__name__) + + +class BaseEnvelope(ABC): + def _parse_user_dict_schema(self, user_event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + logger.debug("parsing user dictionary schema") + try: + return inbound_schema_model(**user_event) + except (ValidationError, TypeError): + logger.exception("Valdation exception while extracting user custom schema") + raise + + def _parse_user_json_string_schema(self, user_event: str, inbound_schema_model: BaseModel) -> Any: + logger.debug("parsing user dictionary schema") + try: + return inbound_schema_model.parse_raw(user_event) + except (ValidationError, TypeError): + logger.exception("Valdation exception while extracting user custom schema") + raise + + @abstractmethod + def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + return NotImplemented + + +class UserEnvelope(BaseEnvelope): + def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + try: + return inbound_schema_model(**event) + except (ValidationError, TypeError): + logger.exception("Valdation exception received from input user custom envelopes event") + raise diff --git a/aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py b/aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py new file mode 100644 index 00000000000..7d841fe3da4 --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py @@ -0,0 +1,32 @@ +import logging +from typing import Any, Dict + +from pydantic import BaseModel, ValidationError + +from ..schemas import DynamoDBSchema +from .base import BaseEnvelope + +logger = logging.getLogger(__name__) + + +class DynamoDBEnvelope(BaseEnvelope): + def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + try: + parsed_envelope = DynamoDBSchema(**event) + except (ValidationError, TypeError): + logger.exception("Valdation exception received from input dynamodb stream event") + raise + output = [] + for record in parsed_envelope.Records: + parsed_new_image = ( + {} + if not record.dynamodb.NewImage + else self._parse_user_dict_schema(record.dynamodb.NewImage, inbound_schema_model) + ) # noqa: E501 + parsed_old_image = ( + {} + if not record.dynamodb.OldImage + else self._parse_user_dict_schema(record.dynamodb.OldImage, inbound_schema_model) + ) # noqa: E501 + output.append({"new": parsed_new_image, "old": parsed_old_image}) + return output diff --git a/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py b/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py new file mode 100644 index 00000000000..fe43f64ebcc --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py @@ -0,0 +1,19 @@ +import logging +from typing import Any, Dict + +from pydantic import BaseModel, ValidationError + +from ..schemas import EventBridgeSchema +from .base import BaseEnvelope + +logger = logging.getLogger(__name__) + + +class EventBridgeEnvelope(BaseEnvelope): + def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + try: + parsed_envelope = EventBridgeSchema(**event) + except (ValidationError, TypeError): + logger.exception("Valdation exception received from input eventbridge event") + raise + return self._parse_user_dict_schema(parsed_envelope.detail, inbound_schema_model) diff --git a/aws_lambda_powertools/utilities/validation/schemas/__init__.py b/aws_lambda_powertools/utilities/validation/schemas/__init__.py new file mode 100644 index 00000000000..4d014e44d63 --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/schemas/__init__.py @@ -0,0 +1,11 @@ +from .dynamodb import DynamoDBSchema +from .event_bridge import EventBridgeSchema +from .sns import SnsSchema +from .sqs import SqsSchema + +__all__ = [ + "DynamoDBSchema", + "EventBridgeSchema", + "SnsSchema", + "SqsSchema", +] diff --git a/aws_lambda_powertools/validation/schemas.py b/aws_lambda_powertools/utilities/validation/schemas/dynamodb.py similarity index 78% rename from aws_lambda_powertools/validation/schemas.py rename to aws_lambda_powertools/utilities/validation/schemas/dynamodb.py index bcdf082eeb3..47943fec937 100644 --- a/aws_lambda_powertools/validation/schemas.py +++ b/aws_lambda_powertools/utilities/validation/schemas/dynamodb.py @@ -1,4 +1,4 @@ -from datetime import date, datetime +from datetime import date from typing import Any, Dict, List, Optional from pydantic import BaseModel, root_validator @@ -35,22 +35,3 @@ class DynamoRecordSchema(BaseModel): class DynamoDBSchema(BaseModel): Records: List[DynamoRecordSchema] - - -class EventBridgeSchema(BaseModel): - version: str - id: str # noqa: A003,VNE003 - source: str - account: int - time: datetime - region: str - resources: List[str] - detail: Dict[str, Any] - - -class SqsSchema(BaseModel): - todo: str - - -class SnsSchema(BaseModel): - todo: str diff --git a/aws_lambda_powertools/utilities/validation/schemas/event_bridge.py b/aws_lambda_powertools/utilities/validation/schemas/event_bridge.py new file mode 100644 index 00000000000..f3896f95a98 --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/schemas/event_bridge.py @@ -0,0 +1,15 @@ +from datetime import datetime +from typing import Any, Dict, List + +from pydantic import BaseModel + + +class EventBridgeSchema(BaseModel): + version: str + id: str # noqa: A003,VNE003 + source: str + account: int + time: datetime + region: str + resources: List[str] + detail: Dict[str, Any] diff --git a/aws_lambda_powertools/utilities/validation/schemas/sns.py b/aws_lambda_powertools/utilities/validation/schemas/sns.py new file mode 100644 index 00000000000..cfeec28196b --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/schemas/sns.py @@ -0,0 +1,5 @@ +from pydantic import BaseModel + + +class SnsSchema(BaseModel): + todo: str diff --git a/aws_lambda_powertools/utilities/validation/schemas/sqs.py b/aws_lambda_powertools/utilities/validation/schemas/sqs.py new file mode 100644 index 00000000000..e974d18236a --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/schemas/sqs.py @@ -0,0 +1,5 @@ +from pydantic import BaseModel + + +class SqsSchema(BaseModel): + todo: str diff --git a/aws_lambda_powertools/utilities/validation/validator.py b/aws_lambda_powertools/utilities/validation/validator.py new file mode 100644 index 00000000000..0629f34d61f --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/validator.py @@ -0,0 +1,62 @@ +import logging +from typing import Any, Callable, Dict + +from pydantic import BaseModel, ValidationError + +from aws_lambda_powertools.middleware_factory import lambda_handler_decorator + +from .envelopes.base import BaseEnvelope + +logger = logging.getLogger(__name__) + + +@lambda_handler_decorator +def validator( + handler: Callable[[Dict, Any], Any], + event: Dict[str, Any], + context: Dict[str, Any], + inbound_schema_model: BaseModel, + outbound_schema_model: BaseModel, + envelope: BaseEnvelope, +) -> Any: + """Decorator to create validation for lambda handlers events - both inbound and outbound + + As Lambda follows (event, context) signature we can remove some of the boilerplate + and also capture any exception any Lambda function throws or its response as metadata + + Example + ------- + **Lambda function using validation decorator** + + @validator(inbound=inbound_schema_model, outbound=outbound_schema_model) + def handler(parsed_event_model, context): + ... + + Parameters + ---------- + todo add + + Raises + ------ + err + TypeError or pydantic.ValidationError or any exception raised by the lambda handler itself + """ + lambda_handler_name = handler.__name__ + logger.debug("Validating inbound schema") + parsed_event_model = envelope.parse(event, inbound_schema_model) + try: + logger.debug(f"Calling handler {lambda_handler_name}") + response = handler({"orig": event, "custom": parsed_event_model}, context) + logger.debug("Received lambda handler response successfully") + logger.debug(response) + except Exception: + logger.exception(f"Exception received from {lambda_handler_name}") + raise + + try: + logger.debug("Validating outbound response schema") + outbound_schema_model(**response) + except (ValidationError, TypeError): + logger.exception(f"Validation exception received from {lambda_handler_name} response event") + raise + return response diff --git a/aws_lambda_powertools/validation/__init__.py b/aws_lambda_powertools/validation/__init__.py deleted file mode 100644 index 924f64e70cc..00000000000 --- a/aws_lambda_powertools/validation/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Validation utility -""" diff --git a/aws_lambda_powertools/validation/validator.py b/aws_lambda_powertools/validation/validator.py deleted file mode 100644 index b3ff685007b..00000000000 --- a/aws_lambda_powertools/validation/validator.py +++ /dev/null @@ -1,126 +0,0 @@ -import logging -from abc import ABC, abstractmethod -from typing import Any, Callable, Dict - -from pydantic import BaseModel, ValidationError - -from aws_lambda_powertools.middleware_factory import lambda_handler_decorator -from aws_lambda_powertools.validation.schemas import DynamoDBSchema, EventBridgeSchema - -logger = logging.getLogger(__name__) - - -class Envelope(ABC): - def _parse_user_dict_schema(self, user_event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: - logger.debug("parsing user dictionary schema") - try: - return inbound_schema_model(**user_event) - except (ValidationError, TypeError): - logger.exception("Valdation exception while extracting user custom schema") - raise - - def _parse_user_json_string_schema(self, user_event: str, inbound_schema_model: BaseModel) -> Any: - logger.debug("parsing user dictionary schema") - try: - return inbound_schema_model.parse_raw(user_event) - except (ValidationError, TypeError): - logger.exception("Valdation exception while extracting user custom schema") - raise - - @abstractmethod - def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: - return NotImplemented - - -class UserEnvelope(Envelope): - def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: - try: - return inbound_schema_model(**event) - except (ValidationError, TypeError): - logger.exception("Valdation exception received from input user custom envelope event") - raise - - -class EventBridgeEnvelope(Envelope): - def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: - try: - parsed_envelope = EventBridgeSchema(**event) - except (ValidationError, TypeError): - logger.exception("Valdation exception received from input eventbridge event") - raise - return self._parse_user_dict_schema(parsed_envelope.detail, inbound_schema_model) - - -class DynamoDBEnvelope(Envelope): - def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: - try: - parsed_envelope = DynamoDBSchema(**event) - except (ValidationError, TypeError): - logger.exception("Valdation exception received from input dynamodb stream event") - raise - output = [] - for record in parsed_envelope.Records: - parsed_new_image = ( - {} - if not record.dynamodb.NewImage - else self._parse_user_dict_schema(record.dynamodb.NewImage, inbound_schema_model) - ) # noqa: E501 - parsed_old_image = ( - {} - if not record.dynamodb.OldImage - else self._parse_user_dict_schema(record.dynamodb.OldImage, inbound_schema_model) - ) # noqa: E501 - output.append({"new": parsed_new_image, "old": parsed_old_image}) - return output - - -@lambda_handler_decorator -def validator( - handler: Callable[[Dict, Any], Any], - event: Dict[str, Any], - context: Dict[str, Any], - inbound_schema_model: BaseModel, - outbound_schema_model: BaseModel, - envelope: Envelope, -) -> Any: - """Decorator to create validation for lambda handlers events - both inbound and outbound - - As Lambda follows (event, context) signature we can remove some of the boilerplate - and also capture any exception any Lambda function throws or its response as metadata - - Example - ------- - **Lambda function using validation decorator** - - @validator(inbound=inbound_schema_model, outbound=outbound_schema_model) - def handler(parsed_event_model, context): - ... - - Parameters - ---------- - todo add - - Raises - ------ - err - TypeError or pydantic.ValidationError or any exception raised by the lambda handler itself - """ - lambda_handler_name = handler.__name__ - logger.debug("Validating inbound schema") - parsed_event_model = envelope.parse(event, inbound_schema_model) - try: - logger.debug(f"Calling handler {lambda_handler_name}") - response = handler({"orig": event, "custom": parsed_event_model}, context) - logger.debug("Received lambda handler response successfully") - logger.debug(response) - except Exception: - logger.exception(f"Exception received from {lambda_handler_name}") - raise - - try: - logger.debug("Validating outbound response schema") - outbound_schema_model(**response) - except (ValidationError, TypeError): - logger.exception(f"Validation exception received from {lambda_handler_name} response event") - raise - return response diff --git a/tests/functional/test_validator.py b/tests/functional/test_validator.py index afbdb5242eb..8836b059cfa 100644 --- a/tests/functional/test_validator.py +++ b/tests/functional/test_validator.py @@ -7,7 +7,7 @@ from pydantic import BaseModel from pydantic.error_wrappers import ValidationError -from aws_lambda_powertools.validation.validator import DynamoDBEnvelope, EventBridgeEnvelope, UserEnvelope, validator +from aws_lambda_powertools.utilities.validation import DynamoDBEnvelope, EventBridgeEnvelope, UserEnvelope, validator class OutboundSchema(BaseModel): From bce7aab6dd3fdbb44e6afa57f2bcd7928782cbf0 Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Wed, 26 Aug 2020 21:01:13 +0300 Subject: [PATCH 03/14] added SQS schema & tests and sns skeleton --- .../utilities/validation/__init__.py | 4 +- .../validation/envelopes/__init__.py | 5 + .../utilities/validation/envelopes/base.py | 10 +- .../validation/envelopes/dynamodb.py | 6 +- .../validation/envelopes/event_bridge.py | 7 +- .../utilities/validation/envelopes/sns.py | 20 ++++ .../utilities/validation/envelopes/sqs.py | 23 ++++ .../utilities/validation/schemas/sqs.py | 59 +++++++++- .../utilities/validation/validator.py | 3 +- tests/functional/test_validator.py | 101 +++++++++++++++++- 10 files changed, 222 insertions(+), 16 deletions(-) create mode 100644 aws_lambda_powertools/utilities/validation/envelopes/sns.py create mode 100644 aws_lambda_powertools/utilities/validation/envelopes/sqs.py diff --git a/aws_lambda_powertools/utilities/validation/__init__.py b/aws_lambda_powertools/utilities/validation/__init__.py index bc47c78b0ac..c7042376139 100644 --- a/aws_lambda_powertools/utilities/validation/__init__.py +++ b/aws_lambda_powertools/utilities/validation/__init__.py @@ -1,6 +1,6 @@ """Validation utility """ -from .envelopes import DynamoDBEnvelope, EventBridgeEnvelope, UserEnvelope +from .envelopes import DynamoDBEnvelope, EventBridgeEnvelope, SnsEnvelope, SqsEnvelope, UserEnvelope from .validator import validator -__all__ = ["UserEnvelope", "DynamoDBEnvelope", "EventBridgeEnvelope", "validator"] +__all__ = ["UserEnvelope", "DynamoDBEnvelope", "EventBridgeEnvelope", "SnsEnvelope", "SqsEnvelope", "validator"] diff --git a/aws_lambda_powertools/utilities/validation/envelopes/__init__.py b/aws_lambda_powertools/utilities/validation/envelopes/__init__.py index 31d424a3b99..94b05f7ce0d 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/__init__.py +++ b/aws_lambda_powertools/utilities/validation/envelopes/__init__.py @@ -1,9 +1,14 @@ from .base import UserEnvelope from .dynamodb import DynamoDBEnvelope from .event_bridge import EventBridgeEnvelope +from .sns import SnsEnvelope +from .sqs import SqsEnvelope + __all__ = [ "UserEnvelope", "DynamoDBEnvelope", "EventBridgeEnvelope", + "SqsEnvelope", + "SnsEnvelope" ] diff --git a/aws_lambda_powertools/utilities/validation/envelopes/base.py b/aws_lambda_powertools/utilities/validation/envelopes/base.py index d40bfaa0884..d2fb8068f71 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/base.py +++ b/aws_lambda_powertools/utilities/validation/envelopes/base.py @@ -13,15 +13,19 @@ def _parse_user_dict_schema(self, user_event: Dict[str, Any], inbound_schema_mod try: return inbound_schema_model(**user_event) except (ValidationError, TypeError): - logger.exception("Valdation exception while extracting user custom schema") + logger.exception("Validation exception while extracting user custom schema") raise def _parse_user_json_string_schema(self, user_event: str, inbound_schema_model: BaseModel) -> Any: logger.debug("parsing user dictionary schema") + if inbound_schema_model == str: + logger.debug("input is string, returning") + return user_event + logger.debug("trying to parse as json encoded string") try: return inbound_schema_model.parse_raw(user_event) except (ValidationError, TypeError): - logger.exception("Valdation exception while extracting user custom schema") + logger.exception("Validation exception while extracting user custom schema") raise @abstractmethod @@ -34,5 +38,5 @@ def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: try: return inbound_schema_model(**event) except (ValidationError, TypeError): - logger.exception("Valdation exception received from input user custom envelopes event") + logger.exception("Validation exception received from input user custom envelopes event") raise diff --git a/aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py b/aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py index 7d841fe3da4..0002bc1e237 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py +++ b/aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py @@ -3,8 +3,8 @@ from pydantic import BaseModel, ValidationError -from ..schemas import DynamoDBSchema -from .base import BaseEnvelope +from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.validation.schemas import DynamoDBSchema logger = logging.getLogger(__name__) @@ -14,7 +14,7 @@ def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: try: parsed_envelope = DynamoDBSchema(**event) except (ValidationError, TypeError): - logger.exception("Valdation exception received from input dynamodb stream event") + logger.exception("Validation exception received from input dynamodb stream event") raise output = [] for record in parsed_envelope.Records: diff --git a/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py b/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py index fe43f64ebcc..055124629f5 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py +++ b/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py @@ -3,8 +3,9 @@ from pydantic import BaseModel, ValidationError -from ..schemas import EventBridgeSchema -from .base import BaseEnvelope +from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.validation.schemas import EventBridgeSchema + logger = logging.getLogger(__name__) @@ -14,6 +15,6 @@ def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: try: parsed_envelope = EventBridgeSchema(**event) except (ValidationError, TypeError): - logger.exception("Valdation exception received from input eventbridge event") + logger.exception("Validation exception received from input eventbridge event") raise return self._parse_user_dict_schema(parsed_envelope.detail, inbound_schema_model) diff --git a/aws_lambda_powertools/utilities/validation/envelopes/sns.py b/aws_lambda_powertools/utilities/validation/envelopes/sns.py new file mode 100644 index 00000000000..8bd6457f70f --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/envelopes/sns.py @@ -0,0 +1,20 @@ +import logging +from typing import Any, Dict + +from pydantic import BaseModel, ValidationError + +from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.validation.schemas import SnsSchema + +logger = logging.getLogger(__name__) + + +class SnsEnvelope(BaseEnvelope): + def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + try: + parsed_envelope = SnsSchema(**event) + except (ValidationError, TypeError): + logger.exception("Validation exception received from input sqs event") + raise + ## TODO + return None diff --git a/aws_lambda_powertools/utilities/validation/envelopes/sqs.py b/aws_lambda_powertools/utilities/validation/envelopes/sqs.py new file mode 100644 index 00000000000..6e7e01f0e43 --- /dev/null +++ b/aws_lambda_powertools/utilities/validation/envelopes/sqs.py @@ -0,0 +1,23 @@ +import logging +from typing import Any, Dict + +from pydantic import BaseModel, ValidationError + +from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.validation.schemas import SqsSchema + +logger = logging.getLogger(__name__) + + +class SqsEnvelope(BaseEnvelope): + def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + try: + parsed_envelope = SqsSchema(**event) + except (ValidationError, TypeError): + logger.exception("Validation exception received from input sqs event") + raise + output = [] + for record in parsed_envelope.Records: + parsed_msg = self._parse_user_json_string_schema(record.body, inbound_schema_model) + output.append({"body": parsed_msg, "attributes": record.messageAttributes}) + return output diff --git a/aws_lambda_powertools/utilities/validation/schemas/sqs.py b/aws_lambda_powertools/utilities/validation/schemas/sqs.py index e974d18236a..a8c57e63702 100644 --- a/aws_lambda_powertools/utilities/validation/schemas/sqs.py +++ b/aws_lambda_powertools/utilities/validation/schemas/sqs.py @@ -1,5 +1,60 @@ -from pydantic import BaseModel +import re +from datetime import datetime +from typing import Dict, List, Optional + +from pydantic import BaseModel, root_validator, validator +from typing_extensions import Literal + + +class SqsAttributesSchema(BaseModel): + ApproximateReceiveCount: str + ApproximateFirstReceiveTimestamp: datetime + MessageDeduplicationId: Optional[str] + MessageGroupId: Optional[str] + SenderId: str + SentTimestamp: datetime + SequenceNumber: Optional[str] + + +class SqsMsgAttributeSchema(BaseModel): + stringValue: Optional[str] + binaryValue: Optional[str] + stringListValues: List[str] = [] + binaryListValues: List[str] = [] + dataType: str + + @validator("dataType") + def valid_type(cls, v): # noqa: VNE001 + pattern = re.compile("Number.*|String.*|Binary.*") + if not pattern.match(v): + raise TypeError("data type is invalid") + return v + + @root_validator + def check_str_and_binary_values(cls, values): + binary_val, str_val = values.get("binaryValue", ""), values.get("stringValue", "") + dataType = values.get("dataType") + if not str_val and not binary_val: + raise TypeError("both binaryValue and stringValue are missing") + if dataType.startswith("Binary") and not binary_val: + raise TypeError("binaryValue is missing") + if (dataType.startswith("String") or dataType.startswith("Number")) and not str_val: + raise TypeError("stringValue is missing") + return values + + +class SqsRecordSchema(BaseModel): + messageId: str + receiptHandle: str + body: str + attributes: SqsAttributesSchema + messageAttributes: Dict[str, SqsMsgAttributeSchema] + md5OfBody: str + md5OfMessageAttributes: str + eventSource: Literal["aws:sqs"] + eventSourceARN: str + awsRegion: str class SqsSchema(BaseModel): - todo: str + Records: List[SqsRecordSchema] \ No newline at end of file diff --git a/aws_lambda_powertools/utilities/validation/validator.py b/aws_lambda_powertools/utilities/validation/validator.py index 0629f34d61f..c5ba22d87ba 100644 --- a/aws_lambda_powertools/utilities/validation/validator.py +++ b/aws_lambda_powertools/utilities/validation/validator.py @@ -4,8 +4,7 @@ from pydantic import BaseModel, ValidationError from aws_lambda_powertools.middleware_factory import lambda_handler_decorator - -from .envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope logger = logging.getLogger(__name__) diff --git a/tests/functional/test_validator.py b/tests/functional/test_validator.py index 8836b059cfa..0b2731ea314 100644 --- a/tests/functional/test_validator.py +++ b/tests/functional/test_validator.py @@ -7,7 +7,13 @@ from pydantic import BaseModel from pydantic.error_wrappers import ValidationError -from aws_lambda_powertools.utilities.validation import DynamoDBEnvelope, EventBridgeEnvelope, UserEnvelope, validator +from aws_lambda_powertools.utilities.validation import ( + DynamoDBEnvelope, + EventBridgeEnvelope, + SqsEnvelope, + UserEnvelope, + validator +) class OutboundSchema(BaseModel): @@ -60,6 +66,7 @@ class MyMessage(BaseModel): @validator(inbound_schema_model=MyMessage, outbound_schema_model=OutboundSchema, envelope=DynamoDBEnvelope()) def dynamodb_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: assert event["custom"] + assert len(event["custom"]) == 3 # first record assert not event["custom"][0]["old"] assert event["custom"][0]["new"].message == "hello" @@ -169,3 +176,95 @@ def test_eventbridge_fail_inbound_validation(): event = {"greeting": "hello"} with pytest.raises(ValidationError): eventbridge_handler(event, LambdaContext()) + + +sqs_event_attribs = { + "test4": { + "stringValue": "dfgdfgfd", + "stringListValues": [], + "binaryListValues": [], + "dataType": "String.custom_type", + }, + "test5": {"stringValue": "a,b,c,d", "stringListValues": [], "binaryListValues": [], "dataType": "String"}, + "tes6": {"stringValue": "112.1", "stringListValues": [], "binaryListValues": [], "dataType": "Number.mytype"}, + "test2": {"stringValue": "111", "stringListValues": [], "binaryListValues": [], "dataType": "Number"}, + "test3": {"binaryValue": "w5NNNcOXXXU=", "stringListValues": [], "binaryListValues": [], "dataType": "Binary"}, + "test": {"stringValue": "gfgf", "stringListValues": [], "binaryListValues": [], "dataType": "String"}, +} + + +@validator(inbound_schema_model=MyMessage, outbound_schema_model=OutboundSchema, envelope=SqsEnvelope()) +def sqs_json_body_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: + assert event["custom"] + assert len(event["custom"]) == 1 + assert event["orig"] + assert event["custom"][0]["body"].message == "hello" + assert event["custom"][0]["body"].messageId == 8 + assert len(event["custom"][0]["attributes"]) == len(sqs_event_attribs) + return {"response_code": 200, "message": "working"} + + +def test_sqs_ok_json_string_body_validation(): + event = { + "Records": [ + { + "messageId": "1743e893-cc24-1234-88f8-f80c37dcd923", + "receiptHandle": "AKhXK7azPaZHY0zjmTsdfsdfdsfOgcVob", + "body": '{"message": "hello", "messageId": 8}', + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1598117108660", + "SenderId": "43434dsdfd:sdfds", + "ApproximateFirstReceiveTimestamp": "1598117108667", + }, + "messageAttributes": sqs_event_attribs, + "md5OfBody": "4db76498a982d84c188927c585076a6c", + "md5OfMessageAttributes": "7186428dc148b402947274e0bb41e7ee", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:mytest", + "awsRegion": "us-west-1", + } + ] + } + sqs_json_body_handler(event, LambdaContext()) + + +@validator(inbound_schema_model=str, outbound_schema_model=OutboundSchema, envelope=SqsEnvelope()) +def sqs_string_body_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: + assert event["custom"] + assert len(event["custom"]) == 1 + assert event["orig"] + assert event["custom"][0]["body"] == "hello how are you" + assert len(event["custom"][0]["attributes"]) == len(sqs_event_attribs) + return {"response_code": 200, "message": "working"} + + +def test_sqs_ok_json_string_validation(): + event = { + "Records": [ + { + "messageId": "1743e893-cc24-1234-88f8-f80c37dcd923", + "receiptHandle": "AKhXK7azPaZHY0zjmTsdfsdfdsfOgcVob", + "body": "hello how are you", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1598117108660", + "SenderId": "43434dsdfd:sdfds", + "ApproximateFirstReceiveTimestamp": "1598117108667", + }, + "messageAttributes": sqs_event_attribs, + "md5OfBody": "4db76498a982d84c188927c585076a6c", + "md5OfMessageAttributes": "7186428dc148b402947274e0bb41e7ee", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:mytest", + "awsRegion": "us-west-1", + } + ] + } + sqs_string_body_handler(event, LambdaContext()) + + +def test_sqs_fail_inbound_validation(): + event = {"greeting": "hello"} + with pytest.raises(ValidationError): + sqs_string_body_handler(event, LambdaContext()) From dc64b8ac467c23187066b9dab11a9822b5eee767 Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Wed, 26 Aug 2020 21:32:51 +0300 Subject: [PATCH 04/14] Add validate function, fix flake8 issues --- .../utilities/validation/__init__.py | 12 ++- .../validation/envelopes/__init__.py | 9 +- .../validation/envelopes/event_bridge.py | 1 - .../utilities/validation/envelopes/sns.py | 3 +- .../utilities/validation/schemas/sqs.py | 2 +- .../utilities/validation/validator.py | 10 +++ tests/functional/test_validator.py | 82 ++++++++++++++++--- 7 files changed, 93 insertions(+), 26 deletions(-) diff --git a/aws_lambda_powertools/utilities/validation/__init__.py b/aws_lambda_powertools/utilities/validation/__init__.py index c7042376139..03f2ef598f9 100644 --- a/aws_lambda_powertools/utilities/validation/__init__.py +++ b/aws_lambda_powertools/utilities/validation/__init__.py @@ -1,6 +1,14 @@ """Validation utility """ from .envelopes import DynamoDBEnvelope, EventBridgeEnvelope, SnsEnvelope, SqsEnvelope, UserEnvelope -from .validator import validator +from .validator import validate, validator -__all__ = ["UserEnvelope", "DynamoDBEnvelope", "EventBridgeEnvelope", "SnsEnvelope", "SqsEnvelope", "validator"] +__all__ = [ + "UserEnvelope", + "DynamoDBEnvelope", + "EventBridgeEnvelope", + "SnsEnvelope", + "SqsEnvelope", + "validate", + "validator", +] diff --git a/aws_lambda_powertools/utilities/validation/envelopes/__init__.py b/aws_lambda_powertools/utilities/validation/envelopes/__init__.py index 94b05f7ce0d..a1675ab0a1d 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/__init__.py +++ b/aws_lambda_powertools/utilities/validation/envelopes/__init__.py @@ -4,11 +4,4 @@ from .sns import SnsEnvelope from .sqs import SqsEnvelope - -__all__ = [ - "UserEnvelope", - "DynamoDBEnvelope", - "EventBridgeEnvelope", - "SqsEnvelope", - "SnsEnvelope" -] +__all__ = ["UserEnvelope", "DynamoDBEnvelope", "EventBridgeEnvelope", "SqsEnvelope", "SnsEnvelope"] diff --git a/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py b/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py index 055124629f5..e4db766a6fb 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py +++ b/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py @@ -6,7 +6,6 @@ from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope from aws_lambda_powertools.utilities.validation.schemas import EventBridgeSchema - logger = logging.getLogger(__name__) diff --git a/aws_lambda_powertools/utilities/validation/envelopes/sns.py b/aws_lambda_powertools/utilities/validation/envelopes/sns.py index 8bd6457f70f..c6f50c686b0 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/sns.py +++ b/aws_lambda_powertools/utilities/validation/envelopes/sns.py @@ -12,9 +12,8 @@ class SnsEnvelope(BaseEnvelope): def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: try: - parsed_envelope = SnsSchema(**event) + SnsSchema(**event) except (ValidationError, TypeError): logger.exception("Validation exception received from input sqs event") raise - ## TODO return None diff --git a/aws_lambda_powertools/utilities/validation/schemas/sqs.py b/aws_lambda_powertools/utilities/validation/schemas/sqs.py index a8c57e63702..45e7dabf50d 100644 --- a/aws_lambda_powertools/utilities/validation/schemas/sqs.py +++ b/aws_lambda_powertools/utilities/validation/schemas/sqs.py @@ -57,4 +57,4 @@ class SqsRecordSchema(BaseModel): class SqsSchema(BaseModel): - Records: List[SqsRecordSchema] \ No newline at end of file + Records: List[SqsRecordSchema] diff --git a/aws_lambda_powertools/utilities/validation/validator.py b/aws_lambda_powertools/utilities/validation/validator.py index c5ba22d87ba..2d069d28733 100644 --- a/aws_lambda_powertools/utilities/validation/validator.py +++ b/aws_lambda_powertools/utilities/validation/validator.py @@ -9,6 +9,16 @@ logger = logging.getLogger(__name__) +def validate( + event: Dict[str, Any], schema_model: BaseModel, envelope: BaseEnvelope, return_parsed_event: bool = False +) -> Any: + logger.debug("Validating schema") + parsed_event_model = envelope.parse(event=event, inbound_schema_model=schema_model) + if return_parsed_event: + return parsed_event_model + return None + + @lambda_handler_decorator def validator( handler: Callable[[Dict, Any], Any], diff --git a/tests/functional/test_validator.py b/tests/functional/test_validator.py index 0b2731ea314..42d298933a6 100644 --- a/tests/functional/test_validator.py +++ b/tests/functional/test_validator.py @@ -1,4 +1,3 @@ -import io from http import HTTPStatus from typing import Any, Dict, Optional @@ -12,10 +11,79 @@ EventBridgeEnvelope, SqsEnvelope, UserEnvelope, - validator + validate, + validator, ) +class MyMessage(BaseModel): + message: str + messageId: int + + +def test_validate_function(): + eventbridge_event = { + "version": "0", + "id": "553961c5-5017-5763-6f21-f88d5f5f4b05", + "detail-type": "my func stream event json", + "source": "arn:aws:lambda:eu-west-1:88888888:function:my_func", + "account": "88888888", + "time": "2020-02-11T08:18:09Z", + "region": "eu-west-1", + "resources": ["arn:aws:dynamodb:eu-west-1:88888888:table/stream/2020-02"], + "detail": {"message": "hello", "messageId": 8}, + } + parsed_event = validate(eventbridge_event, MyMessage, EventBridgeEnvelope(), True) + assert parsed_event.dict() == {"message": "hello", "messageId": 8} + + +def test_validate_function_no_return_value(): + eventbridge_event = { + "version": "0", + "id": "553961c5-5017-5763-6f21-f88d5f5f4b05", + "detail-type": "my func stream event json", + "source": "arn:aws:lambda:eu-west-1:88888888:function:my_func", + "account": "88888888", + "time": "2020-02-11T08:18:09Z", + "region": "eu-west-1", + "resources": ["arn:aws:dynamodb:eu-west-1:88888888:table/stream/2020-02"], + "detail": {"message": "hello", "messageId": 8}, + } + parsed_event = validate(eventbridge_event, MyMessage, EventBridgeEnvelope()) + assert parsed_event is None + + +def test_validate_function_fail_envelope(): + eventbridge_event = { + "version": "0", + "id": "553961c5-5017-5763-6f21-f88d5f5f4b05", + "detail-type": "my func stream event json", + "source": "arn:aws:lambda:eu-west-1:88888888:function:my_func", + "time": "2020-02-11T08:18:09Z", + "region": "eu-west-1", + "resources": ["arn:aws:dynamodb:eu-west-1:88888888:table/stream/2020-02"], + "detail": {"message": "hello", "messageId": 8}, + } + with pytest.raises(ValidationError): + validate(eventbridge_event, MyMessage, EventBridgeEnvelope()) + + +def test_validate_function_fail_user_schema(): + eventbridge_event = { + "version": "0", + "id": "553961c5-5017-5763-6f21-f88d5f5f4b05", + "detail-type": "my func stream event json", + "source": "arn:aws:lambda:eu-west-1:88888888:function:my_func", + "account": "88888888", + "time": "2020-02-11T08:18:09Z", + "region": "eu-west-1", + "resources": ["arn:aws:dynamodb:eu-west-1:88888888:table/stream/2020-02"], + "detail": {"mess11age": "hello", "messageId": 8}, + } + with pytest.raises(ValidationError): + validate(eventbridge_event, MyMessage, EventBridgeEnvelope()) + + class OutboundSchema(BaseModel): response_code: HTTPStatus message: str @@ -25,11 +93,6 @@ class InboundSchema(BaseModel): greeting: str -@pytest.fixture -def stdout(): - return io.StringIO() - - @validator(inbound_schema_model=InboundSchema, outbound_schema_model=OutboundSchema, envelope=UserEnvelope()) def my_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: assert event["custom"] @@ -58,11 +121,6 @@ def test_fail_inbound_validation(): my_handler({"this_fails": "hello"}, LambdaContext()) -class MyMessage(BaseModel): - message: str - messageId: int - - @validator(inbound_schema_model=MyMessage, outbound_schema_model=OutboundSchema, envelope=DynamoDBEnvelope()) def dynamodb_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: assert event["custom"] From 637a6963d60b739ecba18f51db0a882aca4ba412 Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Mon, 21 Sep 2020 09:47:56 +0300 Subject: [PATCH 05/14] refactor: change to advanced parser --- .../utilities/advanced_parser/1.json | 45 +++++++++++++++++++ .../__init__.py | 0 .../envelopes/__init__.py | 0 .../envelopes/base.py | 0 .../envelopes/dynamodb.py | 4 +- .../envelopes/event_bridge.py | 4 +- .../envelopes/sns.py | 4 +- .../envelopes/sqs.py | 4 +- .../schemas/__init__.py | 0 .../schemas/dynamodb.py | 0 .../schemas/event_bridge.py | 0 .../schemas/sns.py | 0 .../schemas/sqs.py | 0 .../validator.py | 2 +- ...t_validator.py => test_advanced_parser.py} | 2 +- 15 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 aws_lambda_powertools/utilities/advanced_parser/1.json rename aws_lambda_powertools/utilities/{validation => advanced_parser}/__init__.py (100%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/envelopes/__init__.py (100%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/envelopes/base.py (100%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/envelopes/dynamodb.py (86%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/envelopes/event_bridge.py (76%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/envelopes/sns.py (73%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/envelopes/sqs.py (81%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/schemas/__init__.py (100%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/schemas/dynamodb.py (100%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/schemas/event_bridge.py (100%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/schemas/sns.py (100%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/schemas/sqs.py (100%) rename aws_lambda_powertools/utilities/{validation => advanced_parser}/validator.py (96%) rename tests/functional/{test_validator.py => test_advanced_parser.py} (99%) diff --git a/aws_lambda_powertools/utilities/advanced_parser/1.json b/aws_lambda_powertools/utilities/advanced_parser/1.json new file mode 100644 index 00000000000..c56260e370c --- /dev/null +++ b/aws_lambda_powertools/utilities/advanced_parser/1.json @@ -0,0 +1,45 @@ +[ + { + "Records": [ + { + "EventSource": "aws:sns", + "EventVersion": "1.0", + "EventSubscriptionArn": "arn:aws:sns:eu-west-1:195361640859:GuildTopic:c760f7b8-a747-4c91-9740-7b4870dfe075", + "Sns": { + "Type": "Notification", + "MessageId": "6981dbc3-5042-5e5b-9521-8c7e30010350", + "TopicArn": "arn:aws:sns:eu-west-1:195361640859:GuildTopic", + "Subject": "cool subject", + "Message": "this is my message", + "Timestamp": "2020-08-24T06:28:19.623Z", + "SignatureVersion": "1", + "Signature": "EvSQbV2Et92E4Bbs7Qq6xDSPDLAAgI5gaCT3ReyjxsAqPboLy18EwGoHiNdB7AHsP2wN2cBX/sUw7TLHbob0pQ6to+VDWONDt033CKPv+jYGhrA5sL59gMd6Fd42mbzYPg87jHqKonkMwKK/mQq2q6bYpA1SBVU1RVvZZbCtvft43teoWIJGVHITKni4YAlLQJV1HUrgoDRpXcC/oA4FHWf84ekBQ+RTIXQcPWcsDI5uTHQuVbFFs61WJNNAzUhCZb7/1ITe/TR3ZZNC6iAMYN7eBD8rG8uHeeD+hWwQskO+cmgMjgP/neqYxFEJi5mopkYi+zI5bAs8eE+c8LJh/Q==", + "SigningCertUrl": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem", + "UnsubscribeUrl": "https://sns.eu-west-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:eu-west-1:195361640859:GuildTopic:c760f7b8-a747-4c91-9740-7b4870dfe075", + "MessageAttributes": { + "fsdf": { + "Type": "String", + "Value": "yay" + } + } + } + } + ] + }, + { + "Records": [ + { + "EventSource": "aws:sns", + "EventVersion": "1.0", + "EventSubscriptionArn": "arn:aws:sns:eu-west-1: 195361640859:GuildTopic:c760f7b8-a747-4c91-9740-7b4870dfe075", + "Sns": { + "Type": "Notification", + "MessageId": "04e7f2ae-42f8-537d-bb9b-a51329041193", + "TopicArn": "arn:aws:sns:eu-west-1: 195361640859:GuildTopic", + "Subject": "a short subject for your message", + "Message": "{\"foo\": \"bar\"}" + } + } + ] + } +] \ No newline at end of file diff --git a/aws_lambda_powertools/utilities/validation/__init__.py b/aws_lambda_powertools/utilities/advanced_parser/__init__.py similarity index 100% rename from aws_lambda_powertools/utilities/validation/__init__.py rename to aws_lambda_powertools/utilities/advanced_parser/__init__.py diff --git a/aws_lambda_powertools/utilities/validation/envelopes/__init__.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/__init__.py similarity index 100% rename from aws_lambda_powertools/utilities/validation/envelopes/__init__.py rename to aws_lambda_powertools/utilities/advanced_parser/envelopes/__init__.py diff --git a/aws_lambda_powertools/utilities/validation/envelopes/base.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/base.py similarity index 100% rename from aws_lambda_powertools/utilities/validation/envelopes/base.py rename to aws_lambda_powertools/utilities/advanced_parser/envelopes/base.py diff --git a/aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py similarity index 86% rename from aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py rename to aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py index 0002bc1e237..804f5cddae9 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/dynamodb.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py @@ -3,8 +3,8 @@ from pydantic import BaseModel, ValidationError -from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope -from aws_lambda_powertools.utilities.validation.schemas import DynamoDBSchema +from aws_lambda_powertools.utilities.advanced_parser.envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.advanced_parser.schemas import DynamoDBSchema logger = logging.getLogger(__name__) diff --git a/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/event_bridge.py similarity index 76% rename from aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py rename to aws_lambda_powertools/utilities/advanced_parser/envelopes/event_bridge.py index e4db766a6fb..7c58371d94f 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/event_bridge.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/event_bridge.py @@ -3,8 +3,8 @@ from pydantic import BaseModel, ValidationError -from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope -from aws_lambda_powertools.utilities.validation.schemas import EventBridgeSchema +from aws_lambda_powertools.utilities.advanced_parser.envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.advanced_parser.schemas import EventBridgeSchema logger = logging.getLogger(__name__) diff --git a/aws_lambda_powertools/utilities/validation/envelopes/sns.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/sns.py similarity index 73% rename from aws_lambda_powertools/utilities/validation/envelopes/sns.py rename to aws_lambda_powertools/utilities/advanced_parser/envelopes/sns.py index c6f50c686b0..238bb1166e4 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/sns.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/sns.py @@ -3,8 +3,8 @@ from pydantic import BaseModel, ValidationError -from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope -from aws_lambda_powertools.utilities.validation.schemas import SnsSchema +from aws_lambda_powertools.utilities.advanced_parser.envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.advanced_parser.schemas import SnsSchema logger = logging.getLogger(__name__) diff --git a/aws_lambda_powertools/utilities/validation/envelopes/sqs.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/sqs.py similarity index 81% rename from aws_lambda_powertools/utilities/validation/envelopes/sqs.py rename to aws_lambda_powertools/utilities/advanced_parser/envelopes/sqs.py index 6e7e01f0e43..c63b518ce9a 100644 --- a/aws_lambda_powertools/utilities/validation/envelopes/sqs.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/sqs.py @@ -3,8 +3,8 @@ from pydantic import BaseModel, ValidationError -from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope -from aws_lambda_powertools.utilities.validation.schemas import SqsSchema +from aws_lambda_powertools.utilities.advanced_parser.envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.advanced_parser.schemas import SqsSchema logger = logging.getLogger(__name__) diff --git a/aws_lambda_powertools/utilities/validation/schemas/__init__.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/__init__.py similarity index 100% rename from aws_lambda_powertools/utilities/validation/schemas/__init__.py rename to aws_lambda_powertools/utilities/advanced_parser/schemas/__init__.py diff --git a/aws_lambda_powertools/utilities/validation/schemas/dynamodb.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py similarity index 100% rename from aws_lambda_powertools/utilities/validation/schemas/dynamodb.py rename to aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py diff --git a/aws_lambda_powertools/utilities/validation/schemas/event_bridge.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/event_bridge.py similarity index 100% rename from aws_lambda_powertools/utilities/validation/schemas/event_bridge.py rename to aws_lambda_powertools/utilities/advanced_parser/schemas/event_bridge.py diff --git a/aws_lambda_powertools/utilities/validation/schemas/sns.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/sns.py similarity index 100% rename from aws_lambda_powertools/utilities/validation/schemas/sns.py rename to aws_lambda_powertools/utilities/advanced_parser/schemas/sns.py diff --git a/aws_lambda_powertools/utilities/validation/schemas/sqs.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py similarity index 100% rename from aws_lambda_powertools/utilities/validation/schemas/sqs.py rename to aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py diff --git a/aws_lambda_powertools/utilities/validation/validator.py b/aws_lambda_powertools/utilities/advanced_parser/validator.py similarity index 96% rename from aws_lambda_powertools/utilities/validation/validator.py rename to aws_lambda_powertools/utilities/advanced_parser/validator.py index 2d069d28733..13d3603cbf1 100644 --- a/aws_lambda_powertools/utilities/validation/validator.py +++ b/aws_lambda_powertools/utilities/advanced_parser/validator.py @@ -4,7 +4,7 @@ from pydantic import BaseModel, ValidationError from aws_lambda_powertools.middleware_factory import lambda_handler_decorator -from aws_lambda_powertools.utilities.validation.envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.advanced_parser.envelopes.base import BaseEnvelope logger = logging.getLogger(__name__) diff --git a/tests/functional/test_validator.py b/tests/functional/test_advanced_parser.py similarity index 99% rename from tests/functional/test_validator.py rename to tests/functional/test_advanced_parser.py index 42d298933a6..62fa5aa19aa 100644 --- a/tests/functional/test_validator.py +++ b/tests/functional/test_advanced_parser.py @@ -6,7 +6,7 @@ from pydantic import BaseModel from pydantic.error_wrappers import ValidationError -from aws_lambda_powertools.utilities.validation import ( +from aws_lambda_powertools.utilities.advanced_parser import ( DynamoDBEnvelope, EventBridgeEnvelope, SqsEnvelope, From 34187678c2c2e9fd15bcc4ad8508a37d235b79b0 Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Mon, 21 Sep 2020 13:14:07 +0300 Subject: [PATCH 06/14] refactor: pydantic as optional dependancy, remove lambdaContext --- poetry.lock | 165 ++++++++++------------- pyproject.toml | 8 +- tests/functional/test_advanced_parser.py | 2 +- 3 files changed, 76 insertions(+), 99 deletions(-) diff --git a/poetry.lock b/poetry.lock index 50bbcb1908e..e4d15c23744 100644 --- a/poetry.lock +++ b/poetry.lock @@ -104,23 +104,13 @@ description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.1.0" +version = "20.2.0" [package.extras] dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] - -[[package]] -category = "dev" -description = "AWS Lambda Context class for type checking and testing" -name = "aws-lambda-context" -optional = false -python-versions = ">= 3.6" -version = "1.1.0" - -[package.extras] -tests = ["flake8 (3.7.8)", "isort (4.3.21)", "mypy (0.720)", "black (19.3b0)", "pytest (5.0.1)", "pytest-cov (2.7.1)", "pre-commit (1.17.0)", "bump2version (0.5.10)"] +tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] category = "main" @@ -240,7 +230,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.2.1" +version = "5.3" [package.dependencies] [package.dependencies.toml] @@ -253,7 +243,7 @@ toml = ["toml"] [[package]] category = "dev" description = "A backport of the dataclasses module for Python 3.6" -marker = "python_version >= \"3.6\" and python_version < \"3.7\"" +marker = "python_version >= \"3.6\" and python_version < \"3.7\" or python_version < \"3.7\"" name = "dataclasses" optional = false python-versions = ">=3.6, <3.7" @@ -408,17 +398,6 @@ version = ">=4.3.5" [package.extras] test = ["pytest"] -[[package]] -category = "dev" -description = "Polyfill package for Flake8 plugins" -name = "flake8-polyfill" -optional = false -python-versions = "*" -version = "1.0.2" - -[package.dependencies] -flake8 = "*" - [[package]] category = "dev" description = "A flake8 extension that helps to make more readable variables names" @@ -455,7 +434,7 @@ description = "Python Git Library" name = "gitpython" optional = false python-versions = ">=3.4" -version = "3.1.7" +version = "3.1.8" [package.dependencies] gitdb = ">=4.0.1,<5" @@ -635,8 +614,8 @@ category = "dev" description = "Python Build Reasonableness" name = "pbr" optional = false -python-versions = "*" -version = "5.4.5" +python-versions = ">=2.6" +version = "5.5.0" [[package]] category = "dev" @@ -683,7 +662,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.6.0" [[package]] -category = "main" +category = "dev" description = "Data validation and settings management using python 3.6 type hinting" name = "pydantic" optional = false @@ -810,10 +789,9 @@ description = "Code Metrics in Python" name = "radon" optional = false python-versions = "*" -version = "4.2.0" +version = "4.3.2" [package.dependencies] -flake8-polyfill = "*" future = "*" mando = ">=0.6,<0.7" @@ -821,6 +799,9 @@ mando = ">=0.6,<0.7" python = ">=3.5" version = ">=0.4.1" +[package.extras] +flake8 = ["flake8-polyfill"] + [[package]] category = "dev" description = "Alternative regular expression module, to replace re." @@ -880,7 +861,7 @@ description = "Manage dynamic plugins for Python applications" name = "stevedore" optional = false python-versions = ">=3.6" -version = "3.2.0" +version = "3.2.2" [package.dependencies] pbr = ">=2.0.0,<2.1.0 || >2.1.0" @@ -895,7 +876,7 @@ description = "A collection of helpers and mock objects for unit tests and doc t name = "testfixtures" optional = false python-versions = "*" -version = "6.14.1" +version = "6.14.2" [package.extras] build = ["setuptools-git", "wheel", "twine"] @@ -961,13 +942,16 @@ description = "Monitor code metrics for Python on your CI server" name = "xenon" optional = false python-versions = "*" -version = "0.7.0" +version = "0.7.1" [package.dependencies] PyYAML = ">=4.2b1,<6.0" -radon = ">=4,<5" requests = ">=2.0,<3.0" +[package.dependencies.radon] +extras = ["flake8"] +version = ">=4,<5" + [[package]] category = "dev" description = "Yet another URL library" @@ -998,11 +982,10 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [extras] -jmespath = ["jmespath"] +advanced_parser = [] [metadata] -content-hash = "73a725bb90970d6a99d39eb2fc833937e4576f5fe729d60e9b26d505e08a6ea0" -lock-version = "1.0" +content-hash = "aa893456559cedbe2ef72be416bff7ef407473dbbc1e653b533ab5638189a8ca" python-versions = "^3.6" [metadata.files] @@ -1045,12 +1028,8 @@ atomicwrites = [ {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-20.1.0-py2.py3-none-any.whl", hash = "sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff"}, - {file = "attrs-20.1.0.tar.gz", hash = "sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a"}, -] -aws-lambda-context = [ - {file = "aws-lambda-context-1.1.0.tar.gz", hash = "sha256:b6a6d3360671b25bb171335c7e6510b22e60c6fd5db99803f478c986d3230220"}, - {file = "aws_lambda_context-1.1.0-py3-none-any.whl", hash = "sha256:d03b16aaf8abac30b71bc5d66ed8edadd8805e0d581f73f1e9b4b171635c817d"}, + {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, + {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, ] aws-xray-sdk = [ {file = "aws-xray-sdk-2.6.0.tar.gz", hash = "sha256:abf5b90f740e1f402e23414c9670e59cb9772e235e271fef2bce62b9100cbc77"}, @@ -1089,40 +1068,40 @@ colorama = [ {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, ] coverage = [ - {file = "coverage-5.2.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:40f70f81be4d34f8d491e55936904db5c527b0711b2a46513641a5729783c2e4"}, - {file = "coverage-5.2.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:675192fca634f0df69af3493a48224f211f8db4e84452b08d5fcebb9167adb01"}, - {file = "coverage-5.2.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2fcc8b58953d74d199a1a4d633df8146f0ac36c4e720b4a1997e9b6327af43a8"}, - {file = "coverage-5.2.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:64c4f340338c68c463f1b56e3f2f0423f7b17ba6c3febae80b81f0e093077f59"}, - {file = "coverage-5.2.1-cp27-cp27m-win32.whl", hash = "sha256:52f185ffd3291196dc1aae506b42e178a592b0b60a8610b108e6ad892cfc1bb3"}, - {file = "coverage-5.2.1-cp27-cp27m-win_amd64.whl", hash = "sha256:30bc103587e0d3df9e52cd9da1dd915265a22fad0b72afe54daf840c984b564f"}, - {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9ea749fd447ce7fb1ac71f7616371f04054d969d412d37611716721931e36efd"}, - {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ce7866f29d3025b5b34c2e944e66ebef0d92e4a4f2463f7266daa03a1332a651"}, - {file = "coverage-5.2.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:4869ab1c1ed33953bb2433ce7b894a28d724b7aa76c19b11e2878034a4e4680b"}, - {file = "coverage-5.2.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a3ee9c793ffefe2944d3a2bd928a0e436cd0ac2d9e3723152d6fd5398838ce7d"}, - {file = "coverage-5.2.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28f42dc5172ebdc32622a2c3f7ead1b836cdbf253569ae5673f499e35db0bac3"}, - {file = "coverage-5.2.1-cp35-cp35m-win32.whl", hash = "sha256:e26c993bd4b220429d4ec8c1468eca445a4064a61c74ca08da7429af9bc53bb0"}, - {file = "coverage-5.2.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4186fc95c9febeab5681bc3248553d5ec8c2999b8424d4fc3a39c9cba5796962"}, - {file = "coverage-5.2.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:b360d8fd88d2bad01cb953d81fd2edd4be539df7bfec41e8753fe9f4456a5082"}, - {file = "coverage-5.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1adb6be0dcef0cf9434619d3b892772fdb48e793300f9d762e480e043bd8e716"}, - {file = "coverage-5.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:098a703d913be6fbd146a8c50cc76513d726b022d170e5e98dc56d958fd592fb"}, - {file = "coverage-5.2.1-cp36-cp36m-win32.whl", hash = "sha256:962c44070c281d86398aeb8f64e1bf37816a4dfc6f4c0f114756b14fc575621d"}, - {file = "coverage-5.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1ed2bdb27b4c9fc87058a1cb751c4df8752002143ed393899edb82b131e0546"}, - {file = "coverage-5.2.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:c890728a93fffd0407d7d37c1e6083ff3f9f211c83b4316fae3778417eab9811"}, - {file = "coverage-5.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:538f2fd5eb64366f37c97fdb3077d665fa946d2b6d95447622292f38407f9258"}, - {file = "coverage-5.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:27ca5a2bc04d68f0776f2cdcb8bbd508bbe430a7bf9c02315cd05fb1d86d0034"}, - {file = "coverage-5.2.1-cp37-cp37m-win32.whl", hash = "sha256:aab75d99f3f2874733946a7648ce87a50019eb90baef931698f96b76b6769a46"}, - {file = "coverage-5.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:c2ff24df02a125b7b346c4c9078c8936da06964cc2d276292c357d64378158f8"}, - {file = "coverage-5.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:304fbe451698373dc6653772c72c5d5e883a4aadaf20343592a7abb2e643dae0"}, - {file = "coverage-5.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c96472b8ca5dc135fb0aa62f79b033f02aa434fb03a8b190600a5ae4102df1fd"}, - {file = "coverage-5.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8505e614c983834239f865da2dd336dcf9d72776b951d5dfa5ac36b987726e1b"}, - {file = "coverage-5.2.1-cp38-cp38-win32.whl", hash = "sha256:700997b77cfab016533b3e7dbc03b71d33ee4df1d79f2463a318ca0263fc29dd"}, - {file = "coverage-5.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:46794c815e56f1431c66d81943fa90721bb858375fb36e5903697d5eef88627d"}, - {file = "coverage-5.2.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:16042dc7f8e632e0dcd5206a5095ebd18cb1d005f4c89694f7f8aafd96dd43a3"}, - {file = "coverage-5.2.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c1bbb628ed5192124889b51204de27c575b3ffc05a5a91307e7640eff1d48da4"}, - {file = "coverage-5.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4f6428b55d2916a69f8d6453e48a505c07b2245653b0aa9f0dee38785939f5e4"}, - {file = "coverage-5.2.1-cp39-cp39-win32.whl", hash = "sha256:9e536783a5acee79a9b308be97d3952b662748c4037b6a24cbb339dc7ed8eb89"}, - {file = "coverage-5.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b"}, - {file = "coverage-5.2.1.tar.gz", hash = "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b"}, + {file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"}, + {file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"}, + {file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"}, + {file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"}, + {file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"}, + {file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"}, + {file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"}, + {file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"}, + {file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"}, + {file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"}, + {file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"}, + {file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"}, + {file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"}, + {file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"}, + {file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"}, + {file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"}, + {file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"}, + {file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"}, + {file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"}, + {file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"}, + {file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"}, + {file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"}, + {file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"}, + {file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"}, + {file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"}, + {file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"}, + {file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"}, + {file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"}, + {file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"}, + {file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"}, + {file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"}, + {file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"}, + {file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"}, + {file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"}, ] dataclasses = [ {file = "dataclasses-0.7-py3-none-any.whl", hash = "sha256:3459118f7ede7c8bea0fe795bff7c6c2ce287d01dd226202f7c9ebc0610a7836"}, @@ -1174,10 +1153,6 @@ flake8-isort = [ {file = "flake8-isort-2.9.1.tar.gz", hash = "sha256:0d34b266080e1748412b203a1690792245011706b1858c203476b43460bf3652"}, {file = "flake8_isort-2.9.1-py2.py3-none-any.whl", hash = "sha256:a77df28778a1ac6ac4153339ebd9d252935f3ed4379872d4f8b84986296d8cc3"}, ] -flake8-polyfill = [ - {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, - {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, -] flake8-variables-names = [ {file = "flake8_variables_names-0.0.3.tar.gz", hash = "sha256:d109f5a8fe8c20d64e165287330f1b0160b442d7f96e1527124ba1b63c438347"}, ] @@ -1189,8 +1164,8 @@ gitdb = [ {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, ] gitpython = [ - {file = "GitPython-3.1.7-py3-none-any.whl", hash = "sha256:fa3b92da728a457dd75d62bb5f3eb2816d99a7fe6c67398e260637a40e3fafb5"}, - {file = "GitPython-3.1.7.tar.gz", hash = "sha256:2db287d71a284e22e5c2846042d0602465c7434d910406990d5b74df4afb0858"}, + {file = "GitPython-3.1.8-py3-none-any.whl", hash = "sha256:1858f4fd089abe92ae465f01d5aaaf55e937eca565fb2c1fce35a51b5f85c910"}, + {file = "GitPython-3.1.8.tar.gz", hash = "sha256:080bf8e2cf1a2b907634761c2eaefbe83b69930c94c66ad11b65a8252959f912"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, @@ -1298,8 +1273,8 @@ pathspec = [ {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, ] pbr = [ - {file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"}, - {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"}, + {file = "pbr-5.5.0-py2.py3-none-any.whl", hash = "sha256:5adc0f9fc64319d8df5ca1e4e06eea674c26b80e6f00c530b18ce6a6592ead15"}, + {file = "pbr-5.5.0.tar.gz", hash = "sha256:14bfd98f51c78a3dd22a1ef45cf194ad79eee4a19e8e1a0d5c7f8e81ffe182ea"}, ] pdoc3 = [ {file = "pdoc3-0.7.5.tar.gz", hash = "sha256:ebca75b7fcf23f3b4320abe23339834d3f08c28517718e9d29e555fc38eeb33c"}, @@ -1376,8 +1351,8 @@ pyyaml = [ {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, ] radon = [ - {file = "radon-4.2.0-py2.py3-none-any.whl", hash = "sha256:215e42c8748b5ca8ddf7c061831600b9e73e9c48770a81eeaaeeb066697aee15"}, - {file = "radon-4.2.0.tar.gz", hash = "sha256:b73f6f469c15c9616e0f7ce12080a9ecdee9f2335bdbb5ccea1f2bae26e8d20d"}, + {file = "radon-4.3.2-py2.py3-none-any.whl", hash = "sha256:b991de491eb2edbc2aac8f5f7ebf02b799852f076fa5a73fedf79d144d85e37e"}, + {file = "radon-4.3.2.tar.gz", hash = "sha256:758b3ab345aa86e95f642713612a57da7c7da6d552c4dbfbe397a67601ace7dd"}, ] regex = [ {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"}, @@ -1419,12 +1394,12 @@ smmap = [ {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, ] stevedore = [ - {file = "stevedore-3.2.0-py3-none-any.whl", hash = "sha256:c8f4f0ebbc394e52ddf49de8bcc3cf8ad2b4425ebac494106bbc5e3661ac7633"}, - {file = "stevedore-3.2.0.tar.gz", hash = "sha256:38791aa5bed922b0a844513c5f9ed37774b68edc609e5ab8ab8d8fe0ce4315e5"}, + {file = "stevedore-3.2.2-py3-none-any.whl", hash = "sha256:5e1ab03eaae06ef6ce23859402de785f08d97780ed774948ef16c4652c41bc62"}, + {file = "stevedore-3.2.2.tar.gz", hash = "sha256:f845868b3a3a77a2489d226568abe7328b5c2d4f6a011cc759dfa99144a521f0"}, ] testfixtures = [ - {file = "testfixtures-6.14.1-py2.py3-none-any.whl", hash = "sha256:30566e24a1b34e4d3f8c13abf62557d01eeb4480bcb8f1745467bfb0d415a7d9"}, - {file = "testfixtures-6.14.1.tar.gz", hash = "sha256:58d2b3146d93bc5ddb0cd24e0ccacb13e29bdb61e5c81235c58f7b8ee4470366"}, + {file = "testfixtures-6.14.2-py2.py3-none-any.whl", hash = "sha256:816557888877f498081c1b5c572049b4a2ddffedb77401308ff4cdc1bb9147b7"}, + {file = "testfixtures-6.14.2.tar.gz", hash = "sha256:14d9907390f5f9c7189b3d511b64f34f1072d07cc13b604a57e1bb79029376e3"}, ] toml = [ {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, @@ -1470,8 +1445,8 @@ wrapt = [ {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] xenon = [ - {file = "xenon-0.7.0-py2.py3-none-any.whl", hash = "sha256:83e98f67b7077c95c25c3402aea6203dd2ed6256708b76ed9751e9dbf1aba125"}, - {file = "xenon-0.7.0.tar.gz", hash = "sha256:5e6433c9297d965bf666256a0a030b6e13660ab87680220c4eb07241f101625b"}, + {file = "xenon-0.7.1-py2.py3-none-any.whl", hash = "sha256:33d807ef805a2ed854adfcc7cc998398d5c0626a5ad443e52684b998a4dd4aa3"}, + {file = "xenon-0.7.1.tar.gz", hash = "sha256:38bf283135f0636355ecf6054b6f37226af12faab152161bda1a4f9e4dc5b701"}, ] yarl = [ {file = "yarl-1.5.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:db6db0f45d2c63ddb1a9d18d1b9b22f308e52c83638c26b422d520a815c4b3fb"}, @@ -1495,4 +1470,4 @@ yarl = [ zipp = [ {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, -] \ No newline at end of file +] diff --git a/pyproject.toml b/pyproject.toml index 53aeefb1a7b..5d9b74c6daf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,9 +24,6 @@ fastjsonschema = "^2.14.5" boto3 = "^1.12" jmespath = "^0.10.0" -[tool.poetry.extras] -pydantic = "^1.6.1" - [tool.poetry.dev-dependencies] coverage = {extras = ["toml"], version = "^5.0.3"} pytest = "^5.2" @@ -52,6 +49,11 @@ xenon = "^0.7.0" flake8-eradicate = "^0.3.0" dataclasses = {version = "*", python = "~3.6"} flake8-bugbear = "^20.1.4" +pydantic = ">1.6.0" + + +[tool.poetry.extras] +advanced_parser = ["pydantic"] [tool.coverage.run] source = ["aws_lambda_powertools"] diff --git a/tests/functional/test_advanced_parser.py b/tests/functional/test_advanced_parser.py index 62fa5aa19aa..b740abd240c 100644 --- a/tests/functional/test_advanced_parser.py +++ b/tests/functional/test_advanced_parser.py @@ -2,7 +2,6 @@ from typing import Any, Dict, Optional import pytest -from aws_lambda_context import LambdaContext from pydantic import BaseModel from pydantic.error_wrappers import ValidationError @@ -14,6 +13,7 @@ validate, validator, ) +from aws_lambda_powertools.utilities.typing import LambdaContext class MyMessage(BaseModel): From 47cd711f0787158e3eb60fdae4fb82232b307451 Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Tue, 22 Sep 2020 16:30:58 +0300 Subject: [PATCH 07/14] feat: Advanced parser utility (pydantic) --- .../utilities/advanced_parser/__init__.py | 16 +- .../advanced_parser/envelopes/__init__.py | 8 +- .../advanced_parser/envelopes/base.py | 21 +- .../advanced_parser/envelopes/dynamodb.py | 12 +- .../advanced_parser/envelopes/envelopes.py | 42 +++ .../advanced_parser/envelopes/event_bridge.py | 4 +- .../advanced_parser/envelopes/sns.py | 19 - .../advanced_parser/envelopes/sqs.py | 7 +- .../utilities/advanced_parser/parser.py | 56 +++ .../advanced_parser/schemas/__init__.py | 9 +- .../advanced_parser/schemas/dynamodb.py | 14 +- .../advanced_parser/schemas/event_bridge.py | 5 +- .../utilities/advanced_parser/schemas/sns.py | 5 - .../utilities/advanced_parser/schemas/sqs.py | 3 +- .../utilities/advanced_parser/validator.py | 71 ---- tests/events/eventBridgeEvent.json | 6 +- tests/events/sqsEvent.json | 4 +- tests/functional/parser/__init__.py | 0 tests/functional/parser/schemas.py | 53 +++ tests/functional/parser/test_dynamodb.py | 71 ++++ tests/functional/parser/test_eventbridge.py | 36 ++ tests/functional/parser/test_sqs.py | 68 ++++ tests/functional/parser/utils.py | 12 + tests/functional/test_advanced_parser.py | 328 ------------------ 24 files changed, 384 insertions(+), 486 deletions(-) create mode 100644 aws_lambda_powertools/utilities/advanced_parser/envelopes/envelopes.py delete mode 100644 aws_lambda_powertools/utilities/advanced_parser/envelopes/sns.py create mode 100644 aws_lambda_powertools/utilities/advanced_parser/parser.py delete mode 100644 aws_lambda_powertools/utilities/advanced_parser/schemas/sns.py delete mode 100644 aws_lambda_powertools/utilities/advanced_parser/validator.py create mode 100644 tests/functional/parser/__init__.py create mode 100644 tests/functional/parser/schemas.py create mode 100644 tests/functional/parser/test_dynamodb.py create mode 100644 tests/functional/parser/test_eventbridge.py create mode 100644 tests/functional/parser/test_sqs.py create mode 100644 tests/functional/parser/utils.py delete mode 100644 tests/functional/test_advanced_parser.py diff --git a/aws_lambda_powertools/utilities/advanced_parser/__init__.py b/aws_lambda_powertools/utilities/advanced_parser/__init__.py index 03f2ef598f9..017b5086bb0 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/__init__.py +++ b/aws_lambda_powertools/utilities/advanced_parser/__init__.py @@ -1,14 +1,6 @@ -"""Validation utility +"""Advanced parser utility """ -from .envelopes import DynamoDBEnvelope, EventBridgeEnvelope, SnsEnvelope, SqsEnvelope, UserEnvelope -from .validator import validate, validator +from .envelopes import Envelope, InvalidEnvelopeError, parse_envelope +from .parser import parser -__all__ = [ - "UserEnvelope", - "DynamoDBEnvelope", - "EventBridgeEnvelope", - "SnsEnvelope", - "SqsEnvelope", - "validate", - "validator", -] +__all__ = ["InvalidEnvelopeError", "Envelope", "parse_envelope", "parser"] diff --git a/aws_lambda_powertools/utilities/advanced_parser/envelopes/__init__.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/__init__.py index a1675ab0a1d..5fa4c396ba1 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/envelopes/__init__.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/__init__.py @@ -1,7 +1,3 @@ -from .base import UserEnvelope -from .dynamodb import DynamoDBEnvelope -from .event_bridge import EventBridgeEnvelope -from .sns import SnsEnvelope -from .sqs import SqsEnvelope +from .envelopes import Envelope, InvalidEnvelopeError, parse_envelope -__all__ = ["UserEnvelope", "DynamoDBEnvelope", "EventBridgeEnvelope", "SqsEnvelope", "SnsEnvelope"] +__all__ = ["InvalidEnvelopeError", "Envelope", "parse_envelope"] diff --git a/aws_lambda_powertools/utilities/advanced_parser/envelopes/base.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/base.py index d2fb8068f71..5e00e2c09ac 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/envelopes/base.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/base.py @@ -8,35 +8,26 @@ class BaseEnvelope(ABC): - def _parse_user_dict_schema(self, user_event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + def _parse_user_dict_schema(self, user_event: Dict[str, Any], schema: BaseModel) -> Any: logger.debug("parsing user dictionary schema") try: - return inbound_schema_model(**user_event) + return schema(**user_event) except (ValidationError, TypeError): logger.exception("Validation exception while extracting user custom schema") raise - def _parse_user_json_string_schema(self, user_event: str, inbound_schema_model: BaseModel) -> Any: + def _parse_user_json_string_schema(self, user_event: str, schema: BaseModel) -> Any: logger.debug("parsing user dictionary schema") - if inbound_schema_model == str: + if schema == str: logger.debug("input is string, returning") return user_event logger.debug("trying to parse as json encoded string") try: - return inbound_schema_model.parse_raw(user_event) + return schema.parse_raw(user_event) except (ValidationError, TypeError): logger.exception("Validation exception while extracting user custom schema") raise @abstractmethod - def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + def parse(self, event: Dict[str, Any], schema: BaseModel): return NotImplemented - - -class UserEnvelope(BaseEnvelope): - def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: - try: - return inbound_schema_model(**event) - except (ValidationError, TypeError): - logger.exception("Validation exception received from input user custom envelopes event") - raise diff --git a/aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py index 804f5cddae9..22dad9efb22 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py @@ -10,7 +10,7 @@ class DynamoDBEnvelope(BaseEnvelope): - def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + def parse(self, event: Dict[str, Any], schema: BaseModel) -> Any: try: parsed_envelope = DynamoDBSchema(**event) except (ValidationError, TypeError): @@ -19,14 +19,10 @@ def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: output = [] for record in parsed_envelope.Records: parsed_new_image = ( - {} - if not record.dynamodb.NewImage - else self._parse_user_dict_schema(record.dynamodb.NewImage, inbound_schema_model) + None if not record.dynamodb.NewImage else self._parse_user_dict_schema(record.dynamodb.NewImage, schema) ) # noqa: E501 parsed_old_image = ( - {} - if not record.dynamodb.OldImage - else self._parse_user_dict_schema(record.dynamodb.OldImage, inbound_schema_model) + None if not record.dynamodb.OldImage else self._parse_user_dict_schema(record.dynamodb.OldImage, schema) ) # noqa: E501 - output.append({"new": parsed_new_image, "old": parsed_old_image}) + output.append({"NewImage": parsed_new_image, "OldImage": parsed_old_image}) return output diff --git a/aws_lambda_powertools/utilities/advanced_parser/envelopes/envelopes.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/envelopes.py new file mode 100644 index 00000000000..332c1eadef0 --- /dev/null +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/envelopes.py @@ -0,0 +1,42 @@ +import logging +from enum import Enum +from typing import Any, Dict + +from pydantic import BaseModel + +from aws_lambda_powertools.utilities.advanced_parser.envelopes.base import BaseEnvelope +from aws_lambda_powertools.utilities.advanced_parser.envelopes.dynamodb import DynamoDBEnvelope +from aws_lambda_powertools.utilities.advanced_parser.envelopes.event_bridge import EventBridgeEnvelope +from aws_lambda_powertools.utilities.advanced_parser.envelopes.sqs import SqsEnvelope + +logger = logging.getLogger(__name__) + + +"""Built-in envelopes""" + + +class Envelope(str, Enum): + SQS = "sqs" + EVENTBRIDGE = "eventbridge" + DYNAMODB_STREAM = "dynamodb_stream" + + +class InvalidEnvelopeError(Exception): + """Input envelope is not one of the Envelope enum values""" + + +# enum to BaseEnvelope handler class +__ENVELOPE_MAPPING = { + Envelope.SQS: SqsEnvelope, + Envelope.DYNAMODB_STREAM: DynamoDBEnvelope, + Envelope.EVENTBRIDGE: EventBridgeEnvelope, +} + + +def parse_envelope(event: Dict[str, Any], envelope: Envelope, schema: BaseModel): + envelope_handler: BaseEnvelope = __ENVELOPE_MAPPING.get(envelope) + if envelope_handler is None: + logger.exception("envelope must be an instance of Envelope enum") + raise InvalidEnvelopeError("envelope must be an instance of Envelope enum") + logger.debug(f"Parsing and validating event schema, envelope={str(envelope.value)}") + return envelope_handler().parse(event=event, schema=schema) diff --git a/aws_lambda_powertools/utilities/advanced_parser/envelopes/event_bridge.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/event_bridge.py index 7c58371d94f..5a5c99dcc51 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/envelopes/event_bridge.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/event_bridge.py @@ -10,10 +10,10 @@ class EventBridgeEnvelope(BaseEnvelope): - def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + def parse(self, event: Dict[str, Any], schema: BaseModel) -> Any: try: parsed_envelope = EventBridgeSchema(**event) except (ValidationError, TypeError): logger.exception("Validation exception received from input eventbridge event") raise - return self._parse_user_dict_schema(parsed_envelope.detail, inbound_schema_model) + return self._parse_user_dict_schema(parsed_envelope.detail, schema) diff --git a/aws_lambda_powertools/utilities/advanced_parser/envelopes/sns.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/sns.py deleted file mode 100644 index 238bb1166e4..00000000000 --- a/aws_lambda_powertools/utilities/advanced_parser/envelopes/sns.py +++ /dev/null @@ -1,19 +0,0 @@ -import logging -from typing import Any, Dict - -from pydantic import BaseModel, ValidationError - -from aws_lambda_powertools.utilities.advanced_parser.envelopes.base import BaseEnvelope -from aws_lambda_powertools.utilities.advanced_parser.schemas import SnsSchema - -logger = logging.getLogger(__name__) - - -class SnsEnvelope(BaseEnvelope): - def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: - try: - SnsSchema(**event) - except (ValidationError, TypeError): - logger.exception("Validation exception received from input sqs event") - raise - return None diff --git a/aws_lambda_powertools/utilities/advanced_parser/envelopes/sqs.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/sqs.py index c63b518ce9a..2da218b97d7 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/envelopes/sqs.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/sqs.py @@ -1,5 +1,5 @@ import logging -from typing import Any, Dict +from typing import Any, Dict, List from pydantic import BaseModel, ValidationError @@ -10,7 +10,7 @@ class SqsEnvelope(BaseEnvelope): - def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: + def parse(self, event: Dict[str, Any], schema: BaseModel) -> List[BaseModel]: try: parsed_envelope = SqsSchema(**event) except (ValidationError, TypeError): @@ -18,6 +18,5 @@ def parse(self, event: Dict[str, Any], inbound_schema_model: BaseModel) -> Any: raise output = [] for record in parsed_envelope.Records: - parsed_msg = self._parse_user_json_string_schema(record.body, inbound_schema_model) - output.append({"body": parsed_msg, "attributes": record.messageAttributes}) + output.append(self._parse_user_json_string_schema(record.body, schema)) return output diff --git a/aws_lambda_powertools/utilities/advanced_parser/parser.py b/aws_lambda_powertools/utilities/advanced_parser/parser.py new file mode 100644 index 00000000000..690ea3a59d4 --- /dev/null +++ b/aws_lambda_powertools/utilities/advanced_parser/parser.py @@ -0,0 +1,56 @@ +import logging +from typing import Any, Callable, Dict, Optional + +from pydantic import BaseModel, ValidationError + +from aws_lambda_powertools.middleware_factory import lambda_handler_decorator +from aws_lambda_powertools.utilities.advanced_parser.envelopes import Envelope, parse_envelope + +logger = logging.getLogger(__name__) + + +@lambda_handler_decorator +def parser( + handler: Callable[[Dict, Any], Any], + event: Dict[str, Any], + context: Dict[str, Any], + schema: BaseModel, + envelope: Optional[Envelope] = None, +) -> Any: + """Decorator to conduct advanced parsing & validation for lambda handlers events + + As Lambda follows (event, context) signature we can remove some of the boilerplate + and also capture any exception any Lambda function throws as metadata. + Event will be the parsed & validated BaseModel pydantic object of the input type "schema" + + Example + ------- + **Lambda function using validation decorator** + + @parser(schema=MyBusiness, envelope=envelopes.EVENTBRIDGE) + def handler(event: inbound_schema_model , context: LambdaContext): + ... + + Parameters + ---------- + todo add + + Raises + ------ + err + TypeError or pydantic.ValidationError or any exception raised by the lambda handler itself + """ + lambda_handler_name = handler.__name__ + parsed_event = None + if envelope is None: + try: + logger.debug("Parsing and validating event schema, no envelope is used") + parsed_event = schema(**event) + except (ValidationError, TypeError): + logger.exception("Validation exception received from input event") + raise + else: + parsed_event = parse_envelope(event, envelope, schema) + + logger.debug(f"Calling handler {lambda_handler_name}") + handler(parsed_event, context) diff --git a/aws_lambda_powertools/utilities/advanced_parser/schemas/__init__.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/__init__.py index 4d014e44d63..ac470a16c94 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/schemas/__init__.py +++ b/aws_lambda_powertools/utilities/advanced_parser/schemas/__init__.py @@ -1,11 +1,12 @@ -from .dynamodb import DynamoDBSchema +from .dynamodb import DynamoDBSchema, DynamoRecordSchema, DynamoScheme from .event_bridge import EventBridgeSchema -from .sns import SnsSchema -from .sqs import SqsSchema +from .sqs import SqsRecordSchema, SqsSchema __all__ = [ "DynamoDBSchema", "EventBridgeSchema", - "SnsSchema", + "DynamoScheme", + "DynamoRecordSchema", "SqsSchema", + "SqsRecordSchema", ] diff --git a/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py index 47943fec937..484d25cc7b7 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py +++ b/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py @@ -6,10 +6,10 @@ class DynamoScheme(BaseModel): - ApproximateCreationDateTime: date - Keys: Dict[Literal["id"], Dict[Literal["S"], str]] - NewImage: Optional[Dict[str, Any]] = {} - OldImage: Optional[Dict[str, Any]] = {} + ApproximateCreationDateTime: Optional[date] + Keys: Dict[str, Dict[str, Any]] + NewImage: Optional[Dict[str, Any]] + OldImage: Optional[Dict[str, Any]] SequenceNumber: str SizeBytes: int StreamViewType: Literal["NEW_AND_OLD_IMAGES", "KEYS_ONLY", "NEW_IMAGE", "OLD_IMAGE"] @@ -23,6 +23,11 @@ def check_one_image_exists(cls, values): return values +class UserIdentity(BaseModel): + type: Literal["Service"] # noqa: VNE003, A003 + principalId: Literal["dynamodb.amazonaws.com"] + + class DynamoRecordSchema(BaseModel): eventID: str eventName: Literal["INSERT", "MODIFY", "REMOVE"] @@ -31,6 +36,7 @@ class DynamoRecordSchema(BaseModel): awsRegion: str eventSourceARN: str dynamodb: DynamoScheme + userIdentity: Optional[UserIdentity] class DynamoDBSchema(BaseModel): diff --git a/aws_lambda_powertools/utilities/advanced_parser/schemas/event_bridge.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/event_bridge.py index f3896f95a98..c5e319ac28e 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/schemas/event_bridge.py +++ b/aws_lambda_powertools/utilities/advanced_parser/schemas/event_bridge.py @@ -1,15 +1,16 @@ from datetime import datetime from typing import Any, Dict, List -from pydantic import BaseModel +from pydantic import BaseModel, Field class EventBridgeSchema(BaseModel): version: str id: str # noqa: A003,VNE003 source: str - account: int + account: str time: datetime region: str resources: List[str] + detailtype: str = Field(None, alias="detail-type") detail: Dict[str, Any] diff --git a/aws_lambda_powertools/utilities/advanced_parser/schemas/sns.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/sns.py deleted file mode 100644 index cfeec28196b..00000000000 --- a/aws_lambda_powertools/utilities/advanced_parser/schemas/sns.py +++ /dev/null @@ -1,5 +0,0 @@ -from pydantic import BaseModel - - -class SnsSchema(BaseModel): - todo: str diff --git a/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py index 45e7dabf50d..d4b3c09ddd6 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py +++ b/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py @@ -14,6 +14,7 @@ class SqsAttributesSchema(BaseModel): SenderId: str SentTimestamp: datetime SequenceNumber: Optional[str] + AWSTraceHeader: Optional[str] class SqsMsgAttributeSchema(BaseModel): @@ -50,7 +51,7 @@ class SqsRecordSchema(BaseModel): attributes: SqsAttributesSchema messageAttributes: Dict[str, SqsMsgAttributeSchema] md5OfBody: str - md5OfMessageAttributes: str + md5OfMessageAttributes: Optional[str] eventSource: Literal["aws:sqs"] eventSourceARN: str awsRegion: str diff --git a/aws_lambda_powertools/utilities/advanced_parser/validator.py b/aws_lambda_powertools/utilities/advanced_parser/validator.py deleted file mode 100644 index 13d3603cbf1..00000000000 --- a/aws_lambda_powertools/utilities/advanced_parser/validator.py +++ /dev/null @@ -1,71 +0,0 @@ -import logging -from typing import Any, Callable, Dict - -from pydantic import BaseModel, ValidationError - -from aws_lambda_powertools.middleware_factory import lambda_handler_decorator -from aws_lambda_powertools.utilities.advanced_parser.envelopes.base import BaseEnvelope - -logger = logging.getLogger(__name__) - - -def validate( - event: Dict[str, Any], schema_model: BaseModel, envelope: BaseEnvelope, return_parsed_event: bool = False -) -> Any: - logger.debug("Validating schema") - parsed_event_model = envelope.parse(event=event, inbound_schema_model=schema_model) - if return_parsed_event: - return parsed_event_model - return None - - -@lambda_handler_decorator -def validator( - handler: Callable[[Dict, Any], Any], - event: Dict[str, Any], - context: Dict[str, Any], - inbound_schema_model: BaseModel, - outbound_schema_model: BaseModel, - envelope: BaseEnvelope, -) -> Any: - """Decorator to create validation for lambda handlers events - both inbound and outbound - - As Lambda follows (event, context) signature we can remove some of the boilerplate - and also capture any exception any Lambda function throws or its response as metadata - - Example - ------- - **Lambda function using validation decorator** - - @validator(inbound=inbound_schema_model, outbound=outbound_schema_model) - def handler(parsed_event_model, context): - ... - - Parameters - ---------- - todo add - - Raises - ------ - err - TypeError or pydantic.ValidationError or any exception raised by the lambda handler itself - """ - lambda_handler_name = handler.__name__ - logger.debug("Validating inbound schema") - parsed_event_model = envelope.parse(event, inbound_schema_model) - try: - logger.debug(f"Calling handler {lambda_handler_name}") - response = handler({"orig": event, "custom": parsed_event_model}, context) - logger.debug("Received lambda handler response successfully") - logger.debug(response) - except Exception: - logger.exception(f"Exception received from {lambda_handler_name}") - raise - - try: - logger.debug("Validating outbound response schema") - outbound_schema_model(**response) - except (ValidationError, TypeError): - logger.exception(f"Validation exception received from {lambda_handler_name} response event") - raise - return response diff --git a/tests/events/eventBridgeEvent.json b/tests/events/eventBridgeEvent.json index e8d949001c9..4f059b41492 100644 --- a/tests/events/eventBridgeEvent.json +++ b/tests/events/eventBridgeEvent.json @@ -7,10 +7,10 @@ "time": "2017-12-22T18:43:48Z", "region": "us-west-1", "resources": [ - "arn:aws:ec2:us-west-1:123456789012:instance/ i-1234567890abcdef0" + "arn:aws:ec2:us-west-1:123456789012:instance/i-1234567890abcdef0" ], "detail": { - "instance-id": " i-1234567890abcdef0", + "instance_id": "i-1234567890abcdef0", "state": "terminated" } -} +} \ No newline at end of file diff --git a/tests/events/sqsEvent.json b/tests/events/sqsEvent.json index 7201068d60c..ef03b128943 100644 --- a/tests/events/sqsEvent.json +++ b/tests/events/sqsEvent.json @@ -25,7 +25,7 @@ { "messageId": "2e1424d4-f796-459a-8184-9c92662be6da", "receiptHandle": "AQEBzWwaftRI0KuVm4tP+/7q1rGgNqicHq...", - "body": "Test message.", + "body": "Test message2.", "attributes": { "ApproximateReceiveCount": "1", "SentTimestamp": "1545082650636", @@ -39,4 +39,4 @@ "awsRegion": "us-east-2" } ] -} +} \ No newline at end of file diff --git a/tests/functional/parser/__init__.py b/tests/functional/parser/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/functional/parser/schemas.py b/tests/functional/parser/schemas.py new file mode 100644 index 00000000000..3667601e630 --- /dev/null +++ b/tests/functional/parser/schemas.py @@ -0,0 +1,53 @@ +from typing import Dict, List, Optional + +from pydantic import BaseModel +from typing_extensions import Literal + +from aws_lambda_powertools.utilities.advanced_parser.schemas import ( + DynamoDBSchema, + DynamoRecordSchema, + DynamoScheme, + EventBridgeSchema, + SqsRecordSchema, + SqsSchema, +) + + +class MyDynamoBusiness(BaseModel): + Message: Dict[Literal["S"], str] + Id: Dict[Literal["N"], int] + + +class MyDynamoScheme(DynamoScheme): + NewImage: Optional[MyDynamoBusiness] + OldImage: Optional[MyDynamoBusiness] + + +class MyDynamoRecordSchema(DynamoRecordSchema): + dynamodb: MyDynamoScheme + + +class MyAdvancedDynamoBusiness(DynamoDBSchema): + Records: List[MyDynamoRecordSchema] + + +class MyEventbridgeBusiness(BaseModel): + instance_id: str + state: str + + +class MyAdvancedEventbridgeBusiness(EventBridgeSchema): + detail: MyEventbridgeBusiness + + +class MySqsBusiness(BaseModel): + message: str + username: str + + +class MyAdvancedSqsRecordSchema(SqsRecordSchema): + body: str + + +class MyAdvancedSqsBusiness(SqsSchema): + Records: List[MyAdvancedSqsRecordSchema] diff --git a/tests/functional/parser/test_dynamodb.py b/tests/functional/parser/test_dynamodb.py new file mode 100644 index 00000000000..0cca48db752 --- /dev/null +++ b/tests/functional/parser/test_dynamodb.py @@ -0,0 +1,71 @@ +from typing import Dict, List + +import pytest +from pydantic.error_wrappers import ValidationError + +from aws_lambda_powertools.utilities.advanced_parser.envelopes.envelopes import Envelope +from aws_lambda_powertools.utilities.advanced_parser.parser import parser +from aws_lambda_powertools.utilities.typing import LambdaContext +from tests.functional.parser.schemas import MyAdvancedDynamoBusiness, MyDynamoBusiness +from tests.functional.parser.utils import load_event + + +@parser(schema=MyDynamoBusiness, envelope=Envelope.DYNAMODB_STREAM) +def handle_dynamodb(event: List[Dict[str, MyDynamoBusiness]], context: LambdaContext): + assert len(event) == 2 + assert event[0]["OldImage"] is None + assert event[0]["NewImage"].Message["S"] == "New item!" + assert event[0]["NewImage"].Id["N"] == 101 + assert event[1]["OldImage"].Message["S"] == "New item!" + assert event[1]["OldImage"].Id["N"] == 101 + assert event[1]["NewImage"].Message["S"] == "This item has changed" + assert event[1]["NewImage"].Id["N"] == 101 + + +@parser(schema=MyAdvancedDynamoBusiness) +def handle_dynamodb_no_envelope(event: MyAdvancedDynamoBusiness, context: LambdaContext): + records = event.Records + record = records[0] + assert record.awsRegion == "us-west-2" + dynamodb = record.dynamodb + assert dynamodb is not None + assert dynamodb.ApproximateCreationDateTime is None + keys = dynamodb.Keys + assert keys is not None + id_key = keys["Id"] + assert id_key["N"] == "101" + message_key = dynamodb.NewImage.Message + assert message_key is not None + assert message_key["S"] == "New item!" + assert dynamodb.OldImage is None + assert dynamodb.SequenceNumber == "111" + assert dynamodb.SizeBytes == 26 + assert dynamodb.StreamViewType == "NEW_AND_OLD_IMAGES" + assert record.eventID == "1" + assert record.eventName == "INSERT" + assert record.eventSource == "aws:dynamodb" + assert record.eventSourceARN == "eventsource_arn" + assert record.eventVersion == 1.0 + assert record.userIdentity is None + + +def test_dynamo_db_stream_trigger_event(): + event_dict = load_event("dynamoStreamEvent.json") + handle_dynamodb(event_dict, LambdaContext()) + + +def test_dynamo_db_stream_trigger_event_no_envelope(): + event_dict = load_event("dynamoStreamEvent.json") + handle_dynamodb_no_envelope(event_dict, LambdaContext()) + + +def test_validate_event_does_not_conform_with_schema_no_envelope(): + event_dict = {"hello": "s"} + with pytest.raises(ValidationError): + handle_dynamodb_no_envelope(event_dict, LambdaContext()) + + +def test_validate_event_does_not_conform_with_schema(): + event_dict = {"hello": "s"} + with pytest.raises(ValidationError): + handle_dynamodb(event_dict, LambdaContext()) diff --git a/tests/functional/parser/test_eventbridge.py b/tests/functional/parser/test_eventbridge.py new file mode 100644 index 00000000000..97ddcee1c8a --- /dev/null +++ b/tests/functional/parser/test_eventbridge.py @@ -0,0 +1,36 @@ +from aws_lambda_powertools.utilities.advanced_parser.envelopes.envelopes import Envelope +from aws_lambda_powertools.utilities.advanced_parser.parser import parser +from aws_lambda_powertools.utilities.typing import LambdaContext +from tests.functional.parser.schemas import MyAdvancedEventbridgeBusiness, MyEventbridgeBusiness +from tests.functional.parser.utils import load_event + + +@parser(schema=MyEventbridgeBusiness, envelope=Envelope.EVENTBRIDGE) +def handle_eventbridge(event: MyEventbridgeBusiness, context: LambdaContext): + assert event.instance_id == "i-1234567890abcdef0" + assert event.state == "terminated" + + +@parser(schema=MyAdvancedEventbridgeBusiness) +def handle_eventbridge_no_envelope(event: MyAdvancedEventbridgeBusiness, context: LambdaContext): + assert event.detail.instance_id == "i-1234567890abcdef0" + assert event.detail.state == "terminated" + assert event.id == "6a7e8feb-b491-4cf7-a9f1-bf3703467718" + assert event.version == "0" + assert event.account == "111122223333" + time_str = event.time.strftime("%Y-%m-%dT%H:%M:%SZ") + assert time_str == "2017-12-22T18:43:48Z" + assert event.region == "us-west-1" + assert event.resources == ["arn:aws:ec2:us-west-1:123456789012:instance/i-1234567890abcdef0"] + assert event.source == "aws.ec2" + assert event.detailtype == "EC2 Instance State-change Notification" + + +def test_handle_eventbridge_trigger_event(): + event_dict = load_event("eventBridgeEvent.json") + handle_eventbridge(event_dict, LambdaContext()) + + +def test_handle_eventbridge_trigger_event_no_envelope(): + event_dict = load_event("eventBridgeEvent.json") + handle_eventbridge_no_envelope(event_dict, LambdaContext()) diff --git a/tests/functional/parser/test_sqs.py b/tests/functional/parser/test_sqs.py new file mode 100644 index 00000000000..7b7a91890d4 --- /dev/null +++ b/tests/functional/parser/test_sqs.py @@ -0,0 +1,68 @@ +from typing import List + +from aws_lambda_powertools.utilities.advanced_parser.envelopes.envelopes import Envelope +from aws_lambda_powertools.utilities.advanced_parser.parser import parser +from aws_lambda_powertools.utilities.typing import LambdaContext +from tests.functional.parser.schemas import MyAdvancedSqsBusiness, MySqsBusiness +from tests.functional.parser.utils import load_event +from tests.functional.validator.conftest import sqs_event # noqa: F401 + + +@parser(schema=str, envelope=Envelope.SQS) +def handle_sqs_str_body(event: List[str], context: LambdaContext): + assert len(event) == 2 + assert event[0] == "Test message." + assert event[1] == "Test message2." + + +def test_handle_sqs_trigger_event_str_body(): + event_dict = load_event("sqsEvent.json") + handle_sqs_str_body(event_dict, LambdaContext()) + + +@parser(schema=MySqsBusiness, envelope=Envelope.SQS) +def handle_sqs_json_body(event: List[MySqsBusiness], context: LambdaContext): + assert len(event) == 1 + assert event[0].message == "hello world" + assert event[0].username == "lessa" + + +def test_handle_sqs_trigger_evemt_json_body(sqs_event): # noqa: F811 + handle_sqs_json_body(sqs_event, LambdaContext()) + + +@parser(schema=MyAdvancedSqsBusiness) +def handle_sqs_no_envelope(event: MyAdvancedSqsBusiness, context: LambdaContext): + records = event.Records + record = records[0] + attributes = record.attributes + message_attributes = record.messageAttributes + test_attr = message_attributes["testAttr"] + + assert len(records) == 2 + assert record.messageId == "059f36b4-87a3-44ab-83d2-661975830a7d" + assert record.receiptHandle == "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a..." + assert record.body == "Test message." + assert attributes.AWSTraceHeader is None + assert attributes.ApproximateReceiveCount == "1" + convert_time = int(round(attributes.SentTimestamp.timestamp() * 1000)) + assert convert_time == 1545082649183 + assert attributes.SenderId == "AIDAIENQZJOLO23YVJ4VO" + convert_time = int(round(attributes.ApproximateFirstReceiveTimestamp.timestamp() * 1000)) + assert convert_time == 1545082649185 + assert attributes.SequenceNumber is None + assert attributes.MessageGroupId is None + assert attributes.MessageDeduplicationId is None + assert message_attributes.get("NotFound") is None + assert test_attr.stringValue == "100" + assert test_attr.binaryValue == "base64Str" + assert test_attr.dataType == "Number" + assert record.md5OfBody == "e4e68fb7bd0e697a0ae8f1bb342846b3" + assert record.eventSource == "aws:sqs" + assert record.eventSourceARN == "arn:aws:sqs:us-east-2:123456789012:my-queue" + assert record.awsRegion == "us-east-2" + + +def test_handle_sqs_trigger_event_no_envelope(): + event_dict = load_event("sqsEvent.json") + handle_sqs_no_envelope(event_dict, LambdaContext()) diff --git a/tests/functional/parser/utils.py b/tests/functional/parser/utils.py new file mode 100644 index 00000000000..a9e9641735c --- /dev/null +++ b/tests/functional/parser/utils.py @@ -0,0 +1,12 @@ +import json +import os + + +def get_event_file_path(file_name: str) -> dict: + return os.path.dirname(os.path.realpath(__file__)) + "/../../events/" + file_name + + +def load_event(file_name: str) -> dict: + full_file_name = os.path.dirname(os.path.realpath(__file__)) + "/../../events/" + file_name + with open(full_file_name) as fp: + return json.load(fp) diff --git a/tests/functional/test_advanced_parser.py b/tests/functional/test_advanced_parser.py deleted file mode 100644 index b740abd240c..00000000000 --- a/tests/functional/test_advanced_parser.py +++ /dev/null @@ -1,328 +0,0 @@ -from http import HTTPStatus -from typing import Any, Dict, Optional - -import pytest -from pydantic import BaseModel -from pydantic.error_wrappers import ValidationError - -from aws_lambda_powertools.utilities.advanced_parser import ( - DynamoDBEnvelope, - EventBridgeEnvelope, - SqsEnvelope, - UserEnvelope, - validate, - validator, -) -from aws_lambda_powertools.utilities.typing import LambdaContext - - -class MyMessage(BaseModel): - message: str - messageId: int - - -def test_validate_function(): - eventbridge_event = { - "version": "0", - "id": "553961c5-5017-5763-6f21-f88d5f5f4b05", - "detail-type": "my func stream event json", - "source": "arn:aws:lambda:eu-west-1:88888888:function:my_func", - "account": "88888888", - "time": "2020-02-11T08:18:09Z", - "region": "eu-west-1", - "resources": ["arn:aws:dynamodb:eu-west-1:88888888:table/stream/2020-02"], - "detail": {"message": "hello", "messageId": 8}, - } - parsed_event = validate(eventbridge_event, MyMessage, EventBridgeEnvelope(), True) - assert parsed_event.dict() == {"message": "hello", "messageId": 8} - - -def test_validate_function_no_return_value(): - eventbridge_event = { - "version": "0", - "id": "553961c5-5017-5763-6f21-f88d5f5f4b05", - "detail-type": "my func stream event json", - "source": "arn:aws:lambda:eu-west-1:88888888:function:my_func", - "account": "88888888", - "time": "2020-02-11T08:18:09Z", - "region": "eu-west-1", - "resources": ["arn:aws:dynamodb:eu-west-1:88888888:table/stream/2020-02"], - "detail": {"message": "hello", "messageId": 8}, - } - parsed_event = validate(eventbridge_event, MyMessage, EventBridgeEnvelope()) - assert parsed_event is None - - -def test_validate_function_fail_envelope(): - eventbridge_event = { - "version": "0", - "id": "553961c5-5017-5763-6f21-f88d5f5f4b05", - "detail-type": "my func stream event json", - "source": "arn:aws:lambda:eu-west-1:88888888:function:my_func", - "time": "2020-02-11T08:18:09Z", - "region": "eu-west-1", - "resources": ["arn:aws:dynamodb:eu-west-1:88888888:table/stream/2020-02"], - "detail": {"message": "hello", "messageId": 8}, - } - with pytest.raises(ValidationError): - validate(eventbridge_event, MyMessage, EventBridgeEnvelope()) - - -def test_validate_function_fail_user_schema(): - eventbridge_event = { - "version": "0", - "id": "553961c5-5017-5763-6f21-f88d5f5f4b05", - "detail-type": "my func stream event json", - "source": "arn:aws:lambda:eu-west-1:88888888:function:my_func", - "account": "88888888", - "time": "2020-02-11T08:18:09Z", - "region": "eu-west-1", - "resources": ["arn:aws:dynamodb:eu-west-1:88888888:table/stream/2020-02"], - "detail": {"mess11age": "hello", "messageId": 8}, - } - with pytest.raises(ValidationError): - validate(eventbridge_event, MyMessage, EventBridgeEnvelope()) - - -class OutboundSchema(BaseModel): - response_code: HTTPStatus - message: str - - -class InboundSchema(BaseModel): - greeting: str - - -@validator(inbound_schema_model=InboundSchema, outbound_schema_model=OutboundSchema, envelope=UserEnvelope()) -def my_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: - assert event["custom"] - assert event["orig"] - return {"response_code": 200, "message": "working"} - - -@validator(inbound_schema_model=InboundSchema, outbound_schema_model=OutboundSchema, envelope=UserEnvelope()) -def my_outbound_fail_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: - assert event["custom"] - assert event["orig"] - return {"stuff": 200, "message": "working"} - - -def test_ok_inbound_outbound_validation(): - my_handler({"greeting": "hello"}, LambdaContext()) - - -def test_fail_outbound(): - with pytest.raises(ValidationError): - my_outbound_fail_handler({"greeting": "hello"}, LambdaContext()) - - -def test_fail_inbound_validation(): - with pytest.raises(ValidationError): - my_handler({"this_fails": "hello"}, LambdaContext()) - - -@validator(inbound_schema_model=MyMessage, outbound_schema_model=OutboundSchema, envelope=DynamoDBEnvelope()) -def dynamodb_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: - assert event["custom"] - assert len(event["custom"]) == 3 - # first record - assert not event["custom"][0]["old"] - assert event["custom"][0]["new"].message == "hello" - assert event["custom"][0]["new"].messageId == 8 - # second record - assert event["custom"][1]["new"].message == "new_hello" - assert event["custom"][1]["new"].messageId == 88 - assert event["custom"][1]["old"].message == "hello" - assert event["custom"][1]["old"].messageId == 81 - # third record - assert not event["custom"][2]["new"] - assert event["custom"][2]["old"].message == "hello1" - assert event["custom"][2]["old"].messageId == 82 - assert event["orig"] - - return {"response_code": 200, "message": "working"} - - -def test_dynamodb_fail_inbound_validation(): - event = {"greeting": "hello"} - with pytest.raises(ValidationError): - dynamodb_handler(event, LambdaContext()) - - -def test_dynamodb_ok_inbound_outbound_validation(): - event = { - "Records": [ - { - "eventID": "8ae66d82798e8c34ca4a568d6d2ddb75", - "eventName": "INSERT", - "eventVersion": "1.1", - "eventSource": "aws:dynamodb", - "awsRegion": "eu-west-1", - "dynamodb": { - "ApproximateCreationDateTime": 1583747504.0, - "Keys": {"id": {"S": "a5890cc9-47c7-4667-928b-f072b93f7acd"}}, - "NewImage": {"message": "hello", "messageId": 8}, - "SequenceNumber": "4722000000000004992628049", - "SizeBytes": 215, - "StreamViewType": "NEW_AND_OLD_IMAGES", - }, - "eventSourceARN": "arn:aws:dynamodb/stream/2020-0", - }, - { - "eventID": "8ae66d82798e83333568d6d2ddb75", - "eventName": "MODIFY", - "eventVersion": "1.1", - "eventSource": "aws:dynamodb", - "awsRegion": "eu-west-1", - "dynamodb": { - "ApproximateCreationDateTime": 1583747504.0, - "Keys": {"id": {"S": "a5890cc9-47c7-4667-928b-f072b93f7acd"}}, - "NewImage": {"message": "new_hello", "messageId": 88}, - "OldImage": {"message": "hello", "messageId": 81}, - "SequenceNumber": "4722000000000004992628049", - "SizeBytes": 215, - "StreamViewType": "NEW_AND_OLD_IMAGES", - }, - "eventSourceARN": "arn:aws:dynamodb/stream/2020-0", - }, - { - "eventID": "8ae66d82798e8c34ca4a568d6d2ddb75", - "eventName": "REMOVE", - "eventVersion": "1.1", - "eventSource": "aws:dynamodb", - "awsRegion": "eu-west-1", - "dynamodb": { - "ApproximateCreationDateTime": 1583747504.0, - "Keys": {"id": {"S": "a5890cc9-47c7-4667-928b-f072b93f7acd"}}, - "OldImage": {"message": "hello1", "messageId": 82}, - "SequenceNumber": "4722000000000004992628049", - "SizeBytes": 215, - "StreamViewType": "NEW_AND_OLD_IMAGES", - }, - "eventSourceARN": "arn:aws:dynamodb/stream/2020-0", - }, - ] - } - dynamodb_handler(event, LambdaContext()) - - -@validator(inbound_schema_model=MyMessage, outbound_schema_model=OutboundSchema, envelope=EventBridgeEnvelope()) -def eventbridge_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: - assert event["custom"] - assert event["custom"].messageId == 8 - assert event["custom"].message == "hello" - assert event["orig"] - return {"response_code": 200, "message": "working"} - - -def test_eventbridge_ok_validation(): - event = { - "version": "0", - "id": "553961c5-5017-5763-6f21-f88d5f5f4b05", - "detail-type": "my func stream event json", - "source": "arn:aws:lambda:eu-west-1:88888888:function:my_func", - "account": "88888888", - "time": "2020-02-11T08:18:09Z", - "region": "eu-west-1", - "resources": ["arn:aws:dynamodb:eu-west-1:88888888:table/stream/2020-02"], - "detail": {"message": "hello", "messageId": 8}, - } - eventbridge_handler(event, LambdaContext()) - - -def test_eventbridge_fail_inbound_validation(): - event = {"greeting": "hello"} - with pytest.raises(ValidationError): - eventbridge_handler(event, LambdaContext()) - - -sqs_event_attribs = { - "test4": { - "stringValue": "dfgdfgfd", - "stringListValues": [], - "binaryListValues": [], - "dataType": "String.custom_type", - }, - "test5": {"stringValue": "a,b,c,d", "stringListValues": [], "binaryListValues": [], "dataType": "String"}, - "tes6": {"stringValue": "112.1", "stringListValues": [], "binaryListValues": [], "dataType": "Number.mytype"}, - "test2": {"stringValue": "111", "stringListValues": [], "binaryListValues": [], "dataType": "Number"}, - "test3": {"binaryValue": "w5NNNcOXXXU=", "stringListValues": [], "binaryListValues": [], "dataType": "Binary"}, - "test": {"stringValue": "gfgf", "stringListValues": [], "binaryListValues": [], "dataType": "String"}, -} - - -@validator(inbound_schema_model=MyMessage, outbound_schema_model=OutboundSchema, envelope=SqsEnvelope()) -def sqs_json_body_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: - assert event["custom"] - assert len(event["custom"]) == 1 - assert event["orig"] - assert event["custom"][0]["body"].message == "hello" - assert event["custom"][0]["body"].messageId == 8 - assert len(event["custom"][0]["attributes"]) == len(sqs_event_attribs) - return {"response_code": 200, "message": "working"} - - -def test_sqs_ok_json_string_body_validation(): - event = { - "Records": [ - { - "messageId": "1743e893-cc24-1234-88f8-f80c37dcd923", - "receiptHandle": "AKhXK7azPaZHY0zjmTsdfsdfdsfOgcVob", - "body": '{"message": "hello", "messageId": 8}', - "attributes": { - "ApproximateReceiveCount": "1", - "SentTimestamp": "1598117108660", - "SenderId": "43434dsdfd:sdfds", - "ApproximateFirstReceiveTimestamp": "1598117108667", - }, - "messageAttributes": sqs_event_attribs, - "md5OfBody": "4db76498a982d84c188927c585076a6c", - "md5OfMessageAttributes": "7186428dc148b402947274e0bb41e7ee", - "eventSource": "aws:sqs", - "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:mytest", - "awsRegion": "us-west-1", - } - ] - } - sqs_json_body_handler(event, LambdaContext()) - - -@validator(inbound_schema_model=str, outbound_schema_model=OutboundSchema, envelope=SqsEnvelope()) -def sqs_string_body_handler(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Optional[Any]]: - assert event["custom"] - assert len(event["custom"]) == 1 - assert event["orig"] - assert event["custom"][0]["body"] == "hello how are you" - assert len(event["custom"][0]["attributes"]) == len(sqs_event_attribs) - return {"response_code": 200, "message": "working"} - - -def test_sqs_ok_json_string_validation(): - event = { - "Records": [ - { - "messageId": "1743e893-cc24-1234-88f8-f80c37dcd923", - "receiptHandle": "AKhXK7azPaZHY0zjmTsdfsdfdsfOgcVob", - "body": "hello how are you", - "attributes": { - "ApproximateReceiveCount": "1", - "SentTimestamp": "1598117108660", - "SenderId": "43434dsdfd:sdfds", - "ApproximateFirstReceiveTimestamp": "1598117108667", - }, - "messageAttributes": sqs_event_attribs, - "md5OfBody": "4db76498a982d84c188927c585076a6c", - "md5OfMessageAttributes": "7186428dc148b402947274e0bb41e7ee", - "eventSource": "aws:sqs", - "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:mytest", - "awsRegion": "us-west-1", - } - ] - } - sqs_string_body_handler(event, LambdaContext()) - - -def test_sqs_fail_inbound_validation(): - event = {"greeting": "hello"} - with pytest.raises(ValidationError): - sqs_string_body_handler(event, LambdaContext()) From 6ae17695f11090731ef033103260e2542a9947bd Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Thu, 24 Sep 2020 15:13:04 +0300 Subject: [PATCH 08/14] fix: add only pydantic (+1 squashed commit) Squashed commits: [804f251] fix poetry.lock, revert changes --- README.md | 1 - .../utilities/advanced_parser/1.json | 45 ----- poetry.lock | 166 +++++++++--------- 3 files changed, 79 insertions(+), 133 deletions(-) delete mode 100644 aws_lambda_powertools/utilities/advanced_parser/1.json diff --git a/README.md b/README.md index 4fb16fdf15d..9d0140dc049 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,6 @@ A suite of utilities for AWS Lambda functions to ease adopting best practices su * **[Metrics](https://awslabs.github.io/aws-lambda-powertools-python/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) * **[Bring your own middleware](https://awslabs.github.io/aws-lambda-powertools-python/utilities/middleware_factory/)** - Decorator factory to create your own middleware to run logic before, and after each Lambda invocation * **[Parameters utility](https://awslabs.github.io/aws-lambda-powertools-python/utilities/parameters/)** - Retrieve and cache parameter values from Parameter Store, Secrets Manager, or DynamoDB -* **[Validation](https://)** - ### Installation diff --git a/aws_lambda_powertools/utilities/advanced_parser/1.json b/aws_lambda_powertools/utilities/advanced_parser/1.json deleted file mode 100644 index c56260e370c..00000000000 --- a/aws_lambda_powertools/utilities/advanced_parser/1.json +++ /dev/null @@ -1,45 +0,0 @@ -[ - { - "Records": [ - { - "EventSource": "aws:sns", - "EventVersion": "1.0", - "EventSubscriptionArn": "arn:aws:sns:eu-west-1:195361640859:GuildTopic:c760f7b8-a747-4c91-9740-7b4870dfe075", - "Sns": { - "Type": "Notification", - "MessageId": "6981dbc3-5042-5e5b-9521-8c7e30010350", - "TopicArn": "arn:aws:sns:eu-west-1:195361640859:GuildTopic", - "Subject": "cool subject", - "Message": "this is my message", - "Timestamp": "2020-08-24T06:28:19.623Z", - "SignatureVersion": "1", - "Signature": "EvSQbV2Et92E4Bbs7Qq6xDSPDLAAgI5gaCT3ReyjxsAqPboLy18EwGoHiNdB7AHsP2wN2cBX/sUw7TLHbob0pQ6to+VDWONDt033CKPv+jYGhrA5sL59gMd6Fd42mbzYPg87jHqKonkMwKK/mQq2q6bYpA1SBVU1RVvZZbCtvft43teoWIJGVHITKni4YAlLQJV1HUrgoDRpXcC/oA4FHWf84ekBQ+RTIXQcPWcsDI5uTHQuVbFFs61WJNNAzUhCZb7/1ITe/TR3ZZNC6iAMYN7eBD8rG8uHeeD+hWwQskO+cmgMjgP/neqYxFEJi5mopkYi+zI5bAs8eE+c8LJh/Q==", - "SigningCertUrl": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-a86cb10b4e1f29c941702d737128f7b6.pem", - "UnsubscribeUrl": "https://sns.eu-west-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:eu-west-1:195361640859:GuildTopic:c760f7b8-a747-4c91-9740-7b4870dfe075", - "MessageAttributes": { - "fsdf": { - "Type": "String", - "Value": "yay" - } - } - } - } - ] - }, - { - "Records": [ - { - "EventSource": "aws:sns", - "EventVersion": "1.0", - "EventSubscriptionArn": "arn:aws:sns:eu-west-1: 195361640859:GuildTopic:c760f7b8-a747-4c91-9740-7b4870dfe075", - "Sns": { - "Type": "Notification", - "MessageId": "04e7f2ae-42f8-537d-bb9b-a51329041193", - "TopicArn": "arn:aws:sns:eu-west-1: 195361640859:GuildTopic", - "Subject": "a short subject for your message", - "Message": "{\"foo\": \"bar\"}" - } - } - ] - } -] \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index e4d15c23744..3106dbb17f9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -104,13 +104,12 @@ description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.2.0" +version = "20.1.0" [package.extras] dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] category = "main" @@ -230,7 +229,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.3" +version = "5.2.1" [package.dependencies] [package.dependencies.toml] @@ -243,7 +242,7 @@ toml = ["toml"] [[package]] category = "dev" description = "A backport of the dataclasses module for Python 3.6" -marker = "python_version >= \"3.6\" and python_version < \"3.7\" or python_version < \"3.7\"" +marker = "python_version >= \"3.6\" and python_version < \"3.7\"" name = "dataclasses" optional = false python-versions = ">=3.6, <3.7" @@ -398,6 +397,17 @@ version = ">=4.3.5" [package.extras] test = ["pytest"] +[[package]] +category = "dev" +description = "Polyfill package for Flake8 plugins" +name = "flake8-polyfill" +optional = false +python-versions = "*" +version = "1.0.2" + +[package.dependencies] +flake8 = "*" + [[package]] category = "dev" description = "A flake8 extension that helps to make more readable variables names" @@ -434,7 +444,7 @@ description = "Python Git Library" name = "gitpython" optional = false python-versions = ">=3.4" -version = "3.1.8" +version = "3.1.7" [package.dependencies] gitdb = ">=4.0.1,<5" @@ -614,8 +624,8 @@ category = "dev" description = "Python Build Reasonableness" name = "pbr" optional = false -python-versions = ">=2.6" -version = "5.5.0" +python-versions = "*" +version = "5.4.5" [[package]] category = "dev" @@ -661,24 +671,6 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.6.0" -[[package]] -category = "dev" -description = "Data validation and settings management using python 3.6 type hinting" -name = "pydantic" -optional = false -python-versions = ">=3.6" -version = "1.6.1" - -[package.dependencies] -[package.dependencies.dataclasses] -python = "<3.7" -version = ">=0.6" - -[package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] -typing_extensions = ["typing-extensions (>=3.7.2)"] - [[package]] category = "dev" description = "passive checker of Python programs" @@ -789,9 +781,10 @@ description = "Code Metrics in Python" name = "radon" optional = false python-versions = "*" -version = "4.3.2" +version = "4.2.0" [package.dependencies] +flake8-polyfill = "*" future = "*" mando = ">=0.6,<0.7" @@ -799,9 +792,6 @@ mando = ">=0.6,<0.7" python = ">=3.5" version = ">=0.4.1" -[package.extras] -flake8 = ["flake8-polyfill"] - [[package]] category = "dev" description = "Alternative regular expression module, to replace re." @@ -861,7 +851,7 @@ description = "Manage dynamic plugins for Python applications" name = "stevedore" optional = false python-versions = ">=3.6" -version = "3.2.2" +version = "3.2.0" [package.dependencies] pbr = ">=2.0.0,<2.1.0 || >2.1.0" @@ -876,7 +866,7 @@ description = "A collection of helpers and mock objects for unit tests and doc t name = "testfixtures" optional = false python-versions = "*" -version = "6.14.2" +version = "6.14.1" [package.extras] build = ["setuptools-git", "wheel", "twine"] @@ -942,16 +932,13 @@ description = "Monitor code metrics for Python on your CI server" name = "xenon" optional = false python-versions = "*" -version = "0.7.1" +version = "0.7.0" [package.dependencies] PyYAML = ">=4.2b1,<6.0" +radon = ">=4,<5" requests = ">=2.0,<3.0" -[package.dependencies.radon] -extras = ["flake8"] -version = ">=4,<5" - [[package]] category = "dev" description = "Yet another URL library" @@ -982,10 +969,11 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [extras] -advanced_parser = [] +jmespath = ["jmespath"] [metadata] -content-hash = "aa893456559cedbe2ef72be416bff7ef407473dbbc1e653b533ab5638189a8ca" +content-hash = "73a725bb90970d6a99d39eb2fc833937e4576f5fe729d60e9b26d505e08a6ea0" +lock-version = "1.0" python-versions = "^3.6" [metadata.files] @@ -1028,8 +1016,8 @@ atomicwrites = [ {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, - {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, + {file = "attrs-20.1.0-py2.py3-none-any.whl", hash = "sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff"}, + {file = "attrs-20.1.0.tar.gz", hash = "sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a"}, ] aws-xray-sdk = [ {file = "aws-xray-sdk-2.6.0.tar.gz", hash = "sha256:abf5b90f740e1f402e23414c9670e59cb9772e235e271fef2bce62b9100cbc77"}, @@ -1068,40 +1056,40 @@ colorama = [ {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, ] coverage = [ - {file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"}, - {file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"}, - {file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"}, - {file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"}, - {file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"}, - {file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"}, - {file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"}, - {file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"}, - {file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"}, - {file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"}, - {file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"}, - {file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"}, - {file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"}, - {file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"}, - {file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"}, - {file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"}, - {file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"}, - {file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"}, - {file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"}, - {file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"}, - {file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"}, - {file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"}, - {file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"}, - {file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"}, - {file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"}, - {file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"}, - {file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"}, - {file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"}, - {file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"}, - {file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"}, - {file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"}, - {file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"}, - {file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"}, - {file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"}, + {file = "coverage-5.2.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:40f70f81be4d34f8d491e55936904db5c527b0711b2a46513641a5729783c2e4"}, + {file = "coverage-5.2.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:675192fca634f0df69af3493a48224f211f8db4e84452b08d5fcebb9167adb01"}, + {file = "coverage-5.2.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2fcc8b58953d74d199a1a4d633df8146f0ac36c4e720b4a1997e9b6327af43a8"}, + {file = "coverage-5.2.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:64c4f340338c68c463f1b56e3f2f0423f7b17ba6c3febae80b81f0e093077f59"}, + {file = "coverage-5.2.1-cp27-cp27m-win32.whl", hash = "sha256:52f185ffd3291196dc1aae506b42e178a592b0b60a8610b108e6ad892cfc1bb3"}, + {file = "coverage-5.2.1-cp27-cp27m-win_amd64.whl", hash = "sha256:30bc103587e0d3df9e52cd9da1dd915265a22fad0b72afe54daf840c984b564f"}, + {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9ea749fd447ce7fb1ac71f7616371f04054d969d412d37611716721931e36efd"}, + {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ce7866f29d3025b5b34c2e944e66ebef0d92e4a4f2463f7266daa03a1332a651"}, + {file = "coverage-5.2.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:4869ab1c1ed33953bb2433ce7b894a28d724b7aa76c19b11e2878034a4e4680b"}, + {file = "coverage-5.2.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a3ee9c793ffefe2944d3a2bd928a0e436cd0ac2d9e3723152d6fd5398838ce7d"}, + {file = "coverage-5.2.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28f42dc5172ebdc32622a2c3f7ead1b836cdbf253569ae5673f499e35db0bac3"}, + {file = "coverage-5.2.1-cp35-cp35m-win32.whl", hash = "sha256:e26c993bd4b220429d4ec8c1468eca445a4064a61c74ca08da7429af9bc53bb0"}, + {file = "coverage-5.2.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4186fc95c9febeab5681bc3248553d5ec8c2999b8424d4fc3a39c9cba5796962"}, + {file = "coverage-5.2.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:b360d8fd88d2bad01cb953d81fd2edd4be539df7bfec41e8753fe9f4456a5082"}, + {file = "coverage-5.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1adb6be0dcef0cf9434619d3b892772fdb48e793300f9d762e480e043bd8e716"}, + {file = "coverage-5.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:098a703d913be6fbd146a8c50cc76513d726b022d170e5e98dc56d958fd592fb"}, + {file = "coverage-5.2.1-cp36-cp36m-win32.whl", hash = "sha256:962c44070c281d86398aeb8f64e1bf37816a4dfc6f4c0f114756b14fc575621d"}, + {file = "coverage-5.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1ed2bdb27b4c9fc87058a1cb751c4df8752002143ed393899edb82b131e0546"}, + {file = "coverage-5.2.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:c890728a93fffd0407d7d37c1e6083ff3f9f211c83b4316fae3778417eab9811"}, + {file = "coverage-5.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:538f2fd5eb64366f37c97fdb3077d665fa946d2b6d95447622292f38407f9258"}, + {file = "coverage-5.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:27ca5a2bc04d68f0776f2cdcb8bbd508bbe430a7bf9c02315cd05fb1d86d0034"}, + {file = "coverage-5.2.1-cp37-cp37m-win32.whl", hash = "sha256:aab75d99f3f2874733946a7648ce87a50019eb90baef931698f96b76b6769a46"}, + {file = "coverage-5.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:c2ff24df02a125b7b346c4c9078c8936da06964cc2d276292c357d64378158f8"}, + {file = "coverage-5.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:304fbe451698373dc6653772c72c5d5e883a4aadaf20343592a7abb2e643dae0"}, + {file = "coverage-5.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c96472b8ca5dc135fb0aa62f79b033f02aa434fb03a8b190600a5ae4102df1fd"}, + {file = "coverage-5.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8505e614c983834239f865da2dd336dcf9d72776b951d5dfa5ac36b987726e1b"}, + {file = "coverage-5.2.1-cp38-cp38-win32.whl", hash = "sha256:700997b77cfab016533b3e7dbc03b71d33ee4df1d79f2463a318ca0263fc29dd"}, + {file = "coverage-5.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:46794c815e56f1431c66d81943fa90721bb858375fb36e5903697d5eef88627d"}, + {file = "coverage-5.2.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:16042dc7f8e632e0dcd5206a5095ebd18cb1d005f4c89694f7f8aafd96dd43a3"}, + {file = "coverage-5.2.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c1bbb628ed5192124889b51204de27c575b3ffc05a5a91307e7640eff1d48da4"}, + {file = "coverage-5.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4f6428b55d2916a69f8d6453e48a505c07b2245653b0aa9f0dee38785939f5e4"}, + {file = "coverage-5.2.1-cp39-cp39-win32.whl", hash = "sha256:9e536783a5acee79a9b308be97d3952b662748c4037b6a24cbb339dc7ed8eb89"}, + {file = "coverage-5.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b"}, + {file = "coverage-5.2.1.tar.gz", hash = "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b"}, ] dataclasses = [ {file = "dataclasses-0.7-py3-none-any.whl", hash = "sha256:3459118f7ede7c8bea0fe795bff7c6c2ce287d01dd226202f7c9ebc0610a7836"}, @@ -1153,6 +1141,10 @@ flake8-isort = [ {file = "flake8-isort-2.9.1.tar.gz", hash = "sha256:0d34b266080e1748412b203a1690792245011706b1858c203476b43460bf3652"}, {file = "flake8_isort-2.9.1-py2.py3-none-any.whl", hash = "sha256:a77df28778a1ac6ac4153339ebd9d252935f3ed4379872d4f8b84986296d8cc3"}, ] +flake8-polyfill = [ + {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, + {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, +] flake8-variables-names = [ {file = "flake8_variables_names-0.0.3.tar.gz", hash = "sha256:d109f5a8fe8c20d64e165287330f1b0160b442d7f96e1527124ba1b63c438347"}, ] @@ -1164,8 +1156,8 @@ gitdb = [ {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, ] gitpython = [ - {file = "GitPython-3.1.8-py3-none-any.whl", hash = "sha256:1858f4fd089abe92ae465f01d5aaaf55e937eca565fb2c1fce35a51b5f85c910"}, - {file = "GitPython-3.1.8.tar.gz", hash = "sha256:080bf8e2cf1a2b907634761c2eaefbe83b69930c94c66ad11b65a8252959f912"}, + {file = "GitPython-3.1.7-py3-none-any.whl", hash = "sha256:fa3b92da728a457dd75d62bb5f3eb2816d99a7fe6c67398e260637a40e3fafb5"}, + {file = "GitPython-3.1.7.tar.gz", hash = "sha256:2db287d71a284e22e5c2846042d0602465c7434d910406990d5b74df4afb0858"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, @@ -1273,8 +1265,8 @@ pathspec = [ {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, ] pbr = [ - {file = "pbr-5.5.0-py2.py3-none-any.whl", hash = "sha256:5adc0f9fc64319d8df5ca1e4e06eea674c26b80e6f00c530b18ce6a6592ead15"}, - {file = "pbr-5.5.0.tar.gz", hash = "sha256:14bfd98f51c78a3dd22a1ef45cf194ad79eee4a19e8e1a0d5c7f8e81ffe182ea"}, + {file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"}, + {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"}, ] pdoc3 = [ {file = "pdoc3-0.7.5.tar.gz", hash = "sha256:ebca75b7fcf23f3b4320abe23339834d3f08c28517718e9d29e555fc38eeb33c"}, @@ -1351,8 +1343,8 @@ pyyaml = [ {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, ] radon = [ - {file = "radon-4.3.2-py2.py3-none-any.whl", hash = "sha256:b991de491eb2edbc2aac8f5f7ebf02b799852f076fa5a73fedf79d144d85e37e"}, - {file = "radon-4.3.2.tar.gz", hash = "sha256:758b3ab345aa86e95f642713612a57da7c7da6d552c4dbfbe397a67601ace7dd"}, + {file = "radon-4.2.0-py2.py3-none-any.whl", hash = "sha256:215e42c8748b5ca8ddf7c061831600b9e73e9c48770a81eeaaeeb066697aee15"}, + {file = "radon-4.2.0.tar.gz", hash = "sha256:b73f6f469c15c9616e0f7ce12080a9ecdee9f2335bdbb5ccea1f2bae26e8d20d"}, ] regex = [ {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"}, @@ -1394,12 +1386,12 @@ smmap = [ {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, ] stevedore = [ - {file = "stevedore-3.2.2-py3-none-any.whl", hash = "sha256:5e1ab03eaae06ef6ce23859402de785f08d97780ed774948ef16c4652c41bc62"}, - {file = "stevedore-3.2.2.tar.gz", hash = "sha256:f845868b3a3a77a2489d226568abe7328b5c2d4f6a011cc759dfa99144a521f0"}, + {file = "stevedore-3.2.0-py3-none-any.whl", hash = "sha256:c8f4f0ebbc394e52ddf49de8bcc3cf8ad2b4425ebac494106bbc5e3661ac7633"}, + {file = "stevedore-3.2.0.tar.gz", hash = "sha256:38791aa5bed922b0a844513c5f9ed37774b68edc609e5ab8ab8d8fe0ce4315e5"}, ] testfixtures = [ - {file = "testfixtures-6.14.2-py2.py3-none-any.whl", hash = "sha256:816557888877f498081c1b5c572049b4a2ddffedb77401308ff4cdc1bb9147b7"}, - {file = "testfixtures-6.14.2.tar.gz", hash = "sha256:14d9907390f5f9c7189b3d511b64f34f1072d07cc13b604a57e1bb79029376e3"}, + {file = "testfixtures-6.14.1-py2.py3-none-any.whl", hash = "sha256:30566e24a1b34e4d3f8c13abf62557d01eeb4480bcb8f1745467bfb0d415a7d9"}, + {file = "testfixtures-6.14.1.tar.gz", hash = "sha256:58d2b3146d93bc5ddb0cd24e0ccacb13e29bdb61e5c81235c58f7b8ee4470366"}, ] toml = [ {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, @@ -1445,8 +1437,8 @@ wrapt = [ {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] xenon = [ - {file = "xenon-0.7.1-py2.py3-none-any.whl", hash = "sha256:33d807ef805a2ed854adfcc7cc998398d5c0626a5ad443e52684b998a4dd4aa3"}, - {file = "xenon-0.7.1.tar.gz", hash = "sha256:38bf283135f0636355ecf6054b6f37226af12faab152161bda1a4f9e4dc5b701"}, + {file = "xenon-0.7.0-py2.py3-none-any.whl", hash = "sha256:83e98f67b7077c95c25c3402aea6203dd2ed6256708b76ed9751e9dbf1aba125"}, + {file = "xenon-0.7.0.tar.gz", hash = "sha256:5e6433c9297d965bf666256a0a030b6e13660ab87680220c4eb07241f101625b"}, ] yarl = [ {file = "yarl-1.5.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:db6db0f45d2c63ddb1a9d18d1b9b22f308e52c83638c26b422d520a815c4b3fb"}, @@ -1470,4 +1462,4 @@ yarl = [ zipp = [ {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, -] +] \ No newline at end of file From 19a597fd894bce17ba3f078b7ed99a41436aeb94 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 25 Sep 2020 11:35:53 +0200 Subject: [PATCH 09/14] Revert "fix: remove jmespath extras in Make" This reverts commit 738e261cd21b788eae5247a0a0b5ceb0e0a7e534. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index eeaddf6b7ee..2b841f362c7 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ target: dev: pip install --upgrade pip poetry pre-commit + poetry install --extras "jmespath" pre-commit install dev-docs: From 57b6d234024f382f65ba0b6720eb6cbcf9d766b0 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 25 Sep 2020 11:40:45 +0200 Subject: [PATCH 10/14] poetry update (+2 squashed commits) Squashed commits: [85de91d] fix: pydantic as optional [8ff6bc9] fix: remove only dev extras --- Makefile | 3 +- poetry.lock | 215 ++++++++++++++++++++++++++----------------------- pyproject.toml | 2 +- 3 files changed, 115 insertions(+), 105 deletions(-) diff --git a/Makefile b/Makefile index 2b841f362c7..29c9935875d 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,8 @@ target: dev: pip install --upgrade pip poetry pre-commit - poetry install --extras "jmespath" + poetry install + poetry install --extras "advanced_parser" pre-commit install dev-docs: diff --git a/poetry.lock b/poetry.lock index 3106dbb17f9..3468eca5eb0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -104,12 +104,13 @@ description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.1.0" +version = "20.2.0" [package.extras] dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] category = "main" @@ -229,7 +230,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.2.1" +version = "5.3" [package.dependencies] [package.dependencies.toml] @@ -242,7 +243,7 @@ toml = ["toml"] [[package]] category = "dev" description = "A backport of the dataclasses module for Python 3.6" -marker = "python_version >= \"3.6\" and python_version < \"3.7\"" +marker = "python_version >= \"3.6\" and python_version < \"3.7\" or python_version < \"3.7\"" name = "dataclasses" optional = false python-versions = ">=3.6, <3.7" @@ -397,17 +398,6 @@ version = ">=4.3.5" [package.extras] test = ["pytest"] -[[package]] -category = "dev" -description = "Polyfill package for Flake8 plugins" -name = "flake8-polyfill" -optional = false -python-versions = "*" -version = "1.0.2" - -[package.dependencies] -flake8 = "*" - [[package]] category = "dev" description = "A flake8 extension that helps to make more readable variables names" @@ -444,7 +434,7 @@ description = "Python Git Library" name = "gitpython" optional = false python-versions = ">=3.4" -version = "3.1.7" +version = "3.1.8" [package.dependencies] gitdb = ">=4.0.1,<5" @@ -475,7 +465,7 @@ description = "Read metadata from Python packages" name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.7.0" +version = "2.0.0" [package.dependencies] zipp = ">=0.5" @@ -624,8 +614,8 @@ category = "dev" description = "Python Build Reasonableness" name = "pbr" optional = false -python-versions = "*" -version = "5.4.5" +python-versions = ">=2.6" +version = "5.5.0" [[package]] category = "dev" @@ -671,6 +661,24 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.6.0" +[[package]] +category = "dev" +description = "Data validation and settings management using python 3.6 type hinting" +name = "pydantic" +optional = true +python-versions = ">=3.6" +version = "1.6.1" + +[package.dependencies] +[package.dependencies.dataclasses] +python = "<3.7" +version = ">=0.6" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] +typing_extensions = ["typing-extensions (>=3.7.2)"] + [[package]] category = "dev" description = "passive checker of Python programs" @@ -781,10 +789,9 @@ description = "Code Metrics in Python" name = "radon" optional = false python-versions = "*" -version = "4.2.0" +version = "4.3.2" [package.dependencies] -flake8-polyfill = "*" future = "*" mando = ">=0.6,<0.7" @@ -792,6 +799,9 @@ mando = ">=0.6,<0.7" python = ">=3.5" version = ">=0.4.1" +[package.extras] +flake8 = ["flake8-polyfill"] + [[package]] category = "dev" description = "Alternative regular expression module, to replace re." @@ -851,7 +861,7 @@ description = "Manage dynamic plugins for Python applications" name = "stevedore" optional = false python-versions = ">=3.6" -version = "3.2.0" +version = "3.2.2" [package.dependencies] pbr = ">=2.0.0,<2.1.0 || >2.1.0" @@ -866,7 +876,7 @@ description = "A collection of helpers and mock objects for unit tests and doc t name = "testfixtures" optional = false python-versions = "*" -version = "6.14.1" +version = "6.14.2" [package.extras] build = ["setuptools-git", "wheel", "twine"] @@ -932,20 +942,23 @@ description = "Monitor code metrics for Python on your CI server" name = "xenon" optional = false python-versions = "*" -version = "0.7.0" +version = "0.7.1" [package.dependencies] PyYAML = ">=4.2b1,<6.0" -radon = ">=4,<5" requests = ">=2.0,<3.0" +[package.dependencies.radon] +extras = ["flake8"] +version = ">=4,<5" + [[package]] category = "dev" description = "Yet another URL library" name = "yarl" optional = false python-versions = ">=3.5" -version = "1.5.1" +version = "1.6.0" [package.dependencies] idna = ">=2.0" @@ -962,17 +975,17 @@ marker = "python_version < \"3.8\"" name = "zipp" optional = false python-versions = ">=3.6" -version = "3.1.0" +version = "3.2.0" [package.extras] docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["jaraco.itertools", "func-timeout"] +testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [extras] -jmespath = ["jmespath"] +advanced_parser = [] [metadata] -content-hash = "73a725bb90970d6a99d39eb2fc833937e4576f5fe729d60e9b26d505e08a6ea0" +content-hash = "0b2af58f51056899a11bae6af87144603bd653c65aa4db03d3517fff654a6047" lock-version = "1.0" python-versions = "^3.6" @@ -1016,8 +1029,8 @@ atomicwrites = [ {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-20.1.0-py2.py3-none-any.whl", hash = "sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff"}, - {file = "attrs-20.1.0.tar.gz", hash = "sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a"}, + {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, + {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, ] aws-xray-sdk = [ {file = "aws-xray-sdk-2.6.0.tar.gz", hash = "sha256:abf5b90f740e1f402e23414c9670e59cb9772e235e271fef2bce62b9100cbc77"}, @@ -1056,40 +1069,40 @@ colorama = [ {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, ] coverage = [ - {file = "coverage-5.2.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:40f70f81be4d34f8d491e55936904db5c527b0711b2a46513641a5729783c2e4"}, - {file = "coverage-5.2.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:675192fca634f0df69af3493a48224f211f8db4e84452b08d5fcebb9167adb01"}, - {file = "coverage-5.2.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2fcc8b58953d74d199a1a4d633df8146f0ac36c4e720b4a1997e9b6327af43a8"}, - {file = "coverage-5.2.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:64c4f340338c68c463f1b56e3f2f0423f7b17ba6c3febae80b81f0e093077f59"}, - {file = "coverage-5.2.1-cp27-cp27m-win32.whl", hash = "sha256:52f185ffd3291196dc1aae506b42e178a592b0b60a8610b108e6ad892cfc1bb3"}, - {file = "coverage-5.2.1-cp27-cp27m-win_amd64.whl", hash = "sha256:30bc103587e0d3df9e52cd9da1dd915265a22fad0b72afe54daf840c984b564f"}, - {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9ea749fd447ce7fb1ac71f7616371f04054d969d412d37611716721931e36efd"}, - {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ce7866f29d3025b5b34c2e944e66ebef0d92e4a4f2463f7266daa03a1332a651"}, - {file = "coverage-5.2.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:4869ab1c1ed33953bb2433ce7b894a28d724b7aa76c19b11e2878034a4e4680b"}, - {file = "coverage-5.2.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a3ee9c793ffefe2944d3a2bd928a0e436cd0ac2d9e3723152d6fd5398838ce7d"}, - {file = "coverage-5.2.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28f42dc5172ebdc32622a2c3f7ead1b836cdbf253569ae5673f499e35db0bac3"}, - {file = "coverage-5.2.1-cp35-cp35m-win32.whl", hash = "sha256:e26c993bd4b220429d4ec8c1468eca445a4064a61c74ca08da7429af9bc53bb0"}, - {file = "coverage-5.2.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4186fc95c9febeab5681bc3248553d5ec8c2999b8424d4fc3a39c9cba5796962"}, - {file = "coverage-5.2.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:b360d8fd88d2bad01cb953d81fd2edd4be539df7bfec41e8753fe9f4456a5082"}, - {file = "coverage-5.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1adb6be0dcef0cf9434619d3b892772fdb48e793300f9d762e480e043bd8e716"}, - {file = "coverage-5.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:098a703d913be6fbd146a8c50cc76513d726b022d170e5e98dc56d958fd592fb"}, - {file = "coverage-5.2.1-cp36-cp36m-win32.whl", hash = "sha256:962c44070c281d86398aeb8f64e1bf37816a4dfc6f4c0f114756b14fc575621d"}, - {file = "coverage-5.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1ed2bdb27b4c9fc87058a1cb751c4df8752002143ed393899edb82b131e0546"}, - {file = "coverage-5.2.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:c890728a93fffd0407d7d37c1e6083ff3f9f211c83b4316fae3778417eab9811"}, - {file = "coverage-5.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:538f2fd5eb64366f37c97fdb3077d665fa946d2b6d95447622292f38407f9258"}, - {file = "coverage-5.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:27ca5a2bc04d68f0776f2cdcb8bbd508bbe430a7bf9c02315cd05fb1d86d0034"}, - {file = "coverage-5.2.1-cp37-cp37m-win32.whl", hash = "sha256:aab75d99f3f2874733946a7648ce87a50019eb90baef931698f96b76b6769a46"}, - {file = "coverage-5.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:c2ff24df02a125b7b346c4c9078c8936da06964cc2d276292c357d64378158f8"}, - {file = "coverage-5.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:304fbe451698373dc6653772c72c5d5e883a4aadaf20343592a7abb2e643dae0"}, - {file = "coverage-5.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c96472b8ca5dc135fb0aa62f79b033f02aa434fb03a8b190600a5ae4102df1fd"}, - {file = "coverage-5.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8505e614c983834239f865da2dd336dcf9d72776b951d5dfa5ac36b987726e1b"}, - {file = "coverage-5.2.1-cp38-cp38-win32.whl", hash = "sha256:700997b77cfab016533b3e7dbc03b71d33ee4df1d79f2463a318ca0263fc29dd"}, - {file = "coverage-5.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:46794c815e56f1431c66d81943fa90721bb858375fb36e5903697d5eef88627d"}, - {file = "coverage-5.2.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:16042dc7f8e632e0dcd5206a5095ebd18cb1d005f4c89694f7f8aafd96dd43a3"}, - {file = "coverage-5.2.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c1bbb628ed5192124889b51204de27c575b3ffc05a5a91307e7640eff1d48da4"}, - {file = "coverage-5.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4f6428b55d2916a69f8d6453e48a505c07b2245653b0aa9f0dee38785939f5e4"}, - {file = "coverage-5.2.1-cp39-cp39-win32.whl", hash = "sha256:9e536783a5acee79a9b308be97d3952b662748c4037b6a24cbb339dc7ed8eb89"}, - {file = "coverage-5.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b"}, - {file = "coverage-5.2.1.tar.gz", hash = "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b"}, + {file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"}, + {file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"}, + {file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"}, + {file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"}, + {file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"}, + {file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"}, + {file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"}, + {file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"}, + {file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"}, + {file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"}, + {file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"}, + {file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"}, + {file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"}, + {file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"}, + {file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"}, + {file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"}, + {file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"}, + {file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"}, + {file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"}, + {file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"}, + {file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"}, + {file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"}, + {file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"}, + {file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"}, + {file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"}, + {file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"}, + {file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"}, + {file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"}, + {file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"}, + {file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"}, + {file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"}, + {file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"}, + {file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"}, + {file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"}, ] dataclasses = [ {file = "dataclasses-0.7-py3-none-any.whl", hash = "sha256:3459118f7ede7c8bea0fe795bff7c6c2ce287d01dd226202f7c9ebc0610a7836"}, @@ -1141,10 +1154,6 @@ flake8-isort = [ {file = "flake8-isort-2.9.1.tar.gz", hash = "sha256:0d34b266080e1748412b203a1690792245011706b1858c203476b43460bf3652"}, {file = "flake8_isort-2.9.1-py2.py3-none-any.whl", hash = "sha256:a77df28778a1ac6ac4153339ebd9d252935f3ed4379872d4f8b84986296d8cc3"}, ] -flake8-polyfill = [ - {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, - {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, -] flake8-variables-names = [ {file = "flake8_variables_names-0.0.3.tar.gz", hash = "sha256:d109f5a8fe8c20d64e165287330f1b0160b442d7f96e1527124ba1b63c438347"}, ] @@ -1156,8 +1165,8 @@ gitdb = [ {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, ] gitpython = [ - {file = "GitPython-3.1.7-py3-none-any.whl", hash = "sha256:fa3b92da728a457dd75d62bb5f3eb2816d99a7fe6c67398e260637a40e3fafb5"}, - {file = "GitPython-3.1.7.tar.gz", hash = "sha256:2db287d71a284e22e5c2846042d0602465c7434d910406990d5b74df4afb0858"}, + {file = "GitPython-3.1.8-py3-none-any.whl", hash = "sha256:1858f4fd089abe92ae465f01d5aaaf55e937eca565fb2c1fce35a51b5f85c910"}, + {file = "GitPython-3.1.8.tar.gz", hash = "sha256:080bf8e2cf1a2b907634761c2eaefbe83b69930c94c66ad11b65a8252959f912"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, @@ -1167,8 +1176,8 @@ idna-ssl = [ {file = "idna-ssl-1.1.0.tar.gz", hash = "sha256:a933e3bb13da54383f9e8f35dc4f9cb9eb9b3b78c6b36f311254d6d0d92c6c7c"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, - {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, + {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"}, + {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"}, ] isort = [ {file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"}, @@ -1265,8 +1274,8 @@ pathspec = [ {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, ] pbr = [ - {file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"}, - {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"}, + {file = "pbr-5.5.0-py2.py3-none-any.whl", hash = "sha256:5adc0f9fc64319d8df5ca1e4e06eea674c26b80e6f00c530b18ce6a6592ead15"}, + {file = "pbr-5.5.0.tar.gz", hash = "sha256:14bfd98f51c78a3dd22a1ef45cf194ad79eee4a19e8e1a0d5c7f8e81ffe182ea"}, ] pdoc3 = [ {file = "pdoc3-0.7.5.tar.gz", hash = "sha256:ebca75b7fcf23f3b4320abe23339834d3f08c28517718e9d29e555fc38eeb33c"}, @@ -1343,8 +1352,8 @@ pyyaml = [ {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, ] radon = [ - {file = "radon-4.2.0-py2.py3-none-any.whl", hash = "sha256:215e42c8748b5ca8ddf7c061831600b9e73e9c48770a81eeaaeeb066697aee15"}, - {file = "radon-4.2.0.tar.gz", hash = "sha256:b73f6f469c15c9616e0f7ce12080a9ecdee9f2335bdbb5ccea1f2bae26e8d20d"}, + {file = "radon-4.3.2-py2.py3-none-any.whl", hash = "sha256:b991de491eb2edbc2aac8f5f7ebf02b799852f076fa5a73fedf79d144d85e37e"}, + {file = "radon-4.3.2.tar.gz", hash = "sha256:758b3ab345aa86e95f642713612a57da7c7da6d552c4dbfbe397a67601ace7dd"}, ] regex = [ {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"}, @@ -1386,12 +1395,12 @@ smmap = [ {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, ] stevedore = [ - {file = "stevedore-3.2.0-py3-none-any.whl", hash = "sha256:c8f4f0ebbc394e52ddf49de8bcc3cf8ad2b4425ebac494106bbc5e3661ac7633"}, - {file = "stevedore-3.2.0.tar.gz", hash = "sha256:38791aa5bed922b0a844513c5f9ed37774b68edc609e5ab8ab8d8fe0ce4315e5"}, + {file = "stevedore-3.2.2-py3-none-any.whl", hash = "sha256:5e1ab03eaae06ef6ce23859402de785f08d97780ed774948ef16c4652c41bc62"}, + {file = "stevedore-3.2.2.tar.gz", hash = "sha256:f845868b3a3a77a2489d226568abe7328b5c2d4f6a011cc759dfa99144a521f0"}, ] testfixtures = [ - {file = "testfixtures-6.14.1-py2.py3-none-any.whl", hash = "sha256:30566e24a1b34e4d3f8c13abf62557d01eeb4480bcb8f1745467bfb0d415a7d9"}, - {file = "testfixtures-6.14.1.tar.gz", hash = "sha256:58d2b3146d93bc5ddb0cd24e0ccacb13e29bdb61e5c81235c58f7b8ee4470366"}, + {file = "testfixtures-6.14.2-py2.py3-none-any.whl", hash = "sha256:816557888877f498081c1b5c572049b4a2ddffedb77401308ff4cdc1bb9147b7"}, + {file = "testfixtures-6.14.2.tar.gz", hash = "sha256:14d9907390f5f9c7189b3d511b64f34f1072d07cc13b604a57e1bb79029376e3"}, ] toml = [ {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, @@ -1437,29 +1446,29 @@ wrapt = [ {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] xenon = [ - {file = "xenon-0.7.0-py2.py3-none-any.whl", hash = "sha256:83e98f67b7077c95c25c3402aea6203dd2ed6256708b76ed9751e9dbf1aba125"}, - {file = "xenon-0.7.0.tar.gz", hash = "sha256:5e6433c9297d965bf666256a0a030b6e13660ab87680220c4eb07241f101625b"}, + {file = "xenon-0.7.1-py2.py3-none-any.whl", hash = "sha256:33d807ef805a2ed854adfcc7cc998398d5c0626a5ad443e52684b998a4dd4aa3"}, + {file = "xenon-0.7.1.tar.gz", hash = "sha256:38bf283135f0636355ecf6054b6f37226af12faab152161bda1a4f9e4dc5b701"}, ] yarl = [ - {file = "yarl-1.5.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:db6db0f45d2c63ddb1a9d18d1b9b22f308e52c83638c26b422d520a815c4b3fb"}, - {file = "yarl-1.5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:17668ec6722b1b7a3a05cc0167659f6c95b436d25a36c2d52db0eca7d3f72593"}, - {file = "yarl-1.5.1-cp35-cp35m-win32.whl", hash = "sha256:040b237f58ff7d800e6e0fd89c8439b841f777dd99b4a9cca04d6935564b9409"}, - {file = "yarl-1.5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:f18d68f2be6bf0e89f1521af2b1bb46e66ab0018faafa81d70f358153170a317"}, - {file = "yarl-1.5.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:c52ce2883dc193824989a9b97a76ca86ecd1fa7955b14f87bf367a61b6232511"}, - {file = "yarl-1.5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ce584af5de8830d8701b8979b18fcf450cef9a382b1a3c8ef189bedc408faf1e"}, - {file = "yarl-1.5.1-cp36-cp36m-win32.whl", hash = "sha256:df89642981b94e7db5596818499c4b2219028f2a528c9c37cc1de45bf2fd3a3f"}, - {file = "yarl-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:3a584b28086bc93c888a6c2aa5c92ed1ae20932f078c46509a66dce9ea5533f2"}, - {file = "yarl-1.5.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:da456eeec17fa8aa4594d9a9f27c0b1060b6a75f2419fe0c00609587b2695f4a"}, - {file = "yarl-1.5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bc2f976c0e918659f723401c4f834deb8a8e7798a71be4382e024bcc3f7e23a8"}, - {file = "yarl-1.5.1-cp37-cp37m-win32.whl", hash = "sha256:4439be27e4eee76c7632c2427ca5e73703151b22cae23e64adb243a9c2f565d8"}, - {file = "yarl-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:48e918b05850fffb070a496d2b5f97fc31d15d94ca33d3d08a4f86e26d4e7c5d"}, - {file = "yarl-1.5.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9b930776c0ae0c691776f4d2891ebc5362af86f152dd0da463a6614074cb1b02"}, - {file = "yarl-1.5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b3b9ad80f8b68519cc3372a6ca85ae02cc5a8807723ac366b53c0f089db19e4a"}, - {file = "yarl-1.5.1-cp38-cp38-win32.whl", hash = "sha256:f379b7f83f23fe12823085cd6b906edc49df969eb99757f58ff382349a3303c6"}, - {file = "yarl-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:9102b59e8337f9874638fcfc9ac3734a0cfadb100e47d55c20d0dc6087fb4692"}, - {file = "yarl-1.5.1.tar.gz", hash = "sha256:c22c75b5f394f3d47105045ea551e08a3e804dc7e01b37800ca35b58f856c3d6"}, + {file = "yarl-1.6.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:db9eb8307219d7e09b33bcb43287222ef35cbcf1586ba9472b0a4b833666ada1"}, + {file = "yarl-1.6.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:e31fef4e7b68184545c3d68baec7074532e077bd1906b040ecfba659737df188"}, + {file = "yarl-1.6.0-cp35-cp35m-win32.whl", hash = "sha256:5d84cc36981eb5a8533be79d6c43454c8e6a39ee3118ceaadbd3c029ab2ee580"}, + {file = "yarl-1.6.0-cp35-cp35m-win_amd64.whl", hash = "sha256:5e447e7f3780f44f890360ea973418025e8c0cdcd7d6a1b221d952600fd945dc"}, + {file = "yarl-1.6.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:6f6898429ec3c4cfbef12907047136fd7b9e81a6ee9f105b45505e633427330a"}, + {file = "yarl-1.6.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d088ea9319e49273f25b1c96a3763bf19a882cff774d1792ae6fba34bd40550a"}, + {file = "yarl-1.6.0-cp36-cp36m-win32.whl", hash = "sha256:b7c199d2cbaf892ba0f91ed36d12ff41ecd0dde46cbf64ff4bfe997a3ebc925e"}, + {file = "yarl-1.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:67c5ea0970da882eaf9efcf65b66792557c526f8e55f752194eff8ec722c75c2"}, + {file = "yarl-1.6.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:04a54f126a0732af75e5edc9addeaa2113e2ca7c6fce8974a63549a70a25e50e"}, + {file = "yarl-1.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fcbe419805c9b20db9a51d33b942feddbf6e7fb468cb20686fd7089d4164c12a"}, + {file = "yarl-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:c604998ab8115db802cc55cb1b91619b2831a6128a62ca7eea577fc8ea4d3131"}, + {file = "yarl-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c22607421f49c0cb6ff3ed593a49b6a99c6ffdeaaa6c944cdda83c2393c8864d"}, + {file = "yarl-1.6.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:7ce35944e8e61927a8f4eb78f5bc5d1e6da6d40eadd77e3f79d4e9399e263921"}, + {file = "yarl-1.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c15d71a640fb1f8e98a1423f9c64d7f1f6a3a168f803042eaf3a5b5022fde0c1"}, + {file = "yarl-1.6.0-cp38-cp38-win32.whl", hash = "sha256:3cc860d72ed989f3b1f3abbd6ecf38e412de722fb38b8f1b1a086315cf0d69c5"}, + {file = "yarl-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:e32f0fb443afcfe7f01f95172b66f279938fbc6bdaebe294b0ff6747fb6db020"}, + {file = "yarl-1.6.0.tar.gz", hash = "sha256:61d3ea3c175fe45f1498af868879c6ffeb989d4143ac542163c45538ba5ec21b"}, ] zipp = [ - {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, - {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, -] \ No newline at end of file + {file = "zipp-3.2.0-py3-none-any.whl", hash = "sha256:43f4fa8d8bb313e65d8323a3952ef8756bf40f9a5c3ea7334be23ee4ec8278b6"}, + {file = "zipp-3.2.0.tar.gz", hash = "sha256:b52f22895f4cfce194bc8172f3819ee8de7540aa6d873535a8668b730b8b411f"}, +] diff --git a/pyproject.toml b/pyproject.toml index e7d427f338f..fe46046fb5e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ xenon = "^0.7.0" flake8-eradicate = "^0.3.0" dataclasses = {version = "*", python = "~3.6"} flake8-bugbear = "^20.1.4" -pydantic = ">1.6.0" +pydantic = {version = "^1.6.0", optional = true } [tool.poetry.extras] From ad80cd3755b9dd8ae1532e1b4986a98e17026fdc Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 25 Sep 2020 13:11:18 +0200 Subject: [PATCH 11/14] chore: remove kitchen sink example --- Makefile | 4 +- example/.gitignore | 244 --------------------------- example/README.md | 136 --------------- example/events/event.json | 62 ------- example/hello_world/__init__.py | 0 example/hello_world/app.py | 132 --------------- example/hello_world/requirements.txt | 4 - example/pytest.ini | 3 - example/requirements-dev.txt | 2 - example/samconfig.toml | 9 - example/template.yaml | 57 ------- example/tests/__init__.py | 0 example/tests/test_handler.py | 117 ------------- pytest.ini | 2 +- 14 files changed, 3 insertions(+), 769 deletions(-) delete mode 100644 example/.gitignore delete mode 100644 example/README.md delete mode 100644 example/events/event.json delete mode 100644 example/hello_world/__init__.py delete mode 100644 example/hello_world/app.py delete mode 100644 example/hello_world/requirements.txt delete mode 100644 example/pytest.ini delete mode 100644 example/requirements-dev.txt delete mode 100644 example/samconfig.toml delete mode 100644 example/template.yaml delete mode 100644 example/tests/__init__.py delete mode 100644 example/tests/test_handler.py diff --git a/Makefile b/Makefile index 29c9935875d..19d77a0b508 100644 --- a/Makefile +++ b/Makefile @@ -12,11 +12,11 @@ dev-docs: cd docs && npm install format: - poetry run isort -rc aws_lambda_powertools tests example + poetry run isort -rc aws_lambda_powertools tests poetry run black aws_lambda_powertools tests lint: format - poetry run flake8 aws_lambda_powertools/* tests/* example/* + poetry run flake8 aws_lambda_powertools/* tests/* test: poetry run pytest -vvv --cov=./ --cov-report=xml diff --git a/example/.gitignore b/example/.gitignore deleted file mode 100644 index bbccfb121b2..00000000000 --- a/example/.gitignore +++ /dev/null @@ -1,244 +0,0 @@ - -# Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode - -### Linux ### -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -### OSX ### -*.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### PyCharm ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff: -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/dictionaries - -# Sensitive or high-churn files: -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.xml -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml - -# Gradle: -.idea/**/gradle.xml -.idea/**/libraries - -# CMake -cmake-build-debug/ - -# Mongo Explorer plugin: -.idea/**/mongoSettings.xml - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -/out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Ruby plugin and RubyMine -/.rakeTasks - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -### PyCharm Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - -# Sonarlint plugin -.idea/sonarlint - -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -.pytest_cache/ -nosetests.xml -coverage.xml -*.cover -.hypothesis/ - -# Translations -*.mo -*.pot - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule.* - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ - -### VisualStudioCode ### -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history - -### Windows ### -# Windows thumbnail cache files -Thumbs.db -ehthumbs.db -ehthumbs_vista.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msm -*.msp - -# Windows shortcuts -*.lnk - -# Build folder - -*/build/* - -# End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode diff --git a/example/README.md b/example/README.md deleted file mode 100644 index b19f98f14f1..00000000000 --- a/example/README.md +++ /dev/null @@ -1,136 +0,0 @@ -# Summary - -This example uses [tracer](https://awslabs.github.io/aws-lambda-powertools-python/core/tracer/), [metrics](https://awslabs.github.io/aws-lambda-powertools-python/core/metrics/),and [logger](https://awslabs.github.io/aws-lambda-powertools-python/core/logger/) features, includes all environment variables that can be used, and demonstrates how to explicitly disable tracing while running unit tests - That is not necessary when running within SAM CLI as it detects the local env automatically. - -**Quick commands** - -* **Build**: `sam build --use-container` -* **Invoke locally**: `sam local invoke HelloWorldFunction --event events/event.json` -* **Deploy**: `sam deploy --guided` -* **Unit Tests**: We recommend proceeding with the following commands in a virtual environment - - **Install deps**: `pip install -r hello_world/requirements.txt && pip install -r requirements-dev.txt` - - **Run tests with namespace and service set, and tracing disabled** - - `POWERTOOLS_METRICS_NAMESPACE="Example" POWERTOOLS_SERVICE_NAME="Example" POWERTOOLS_TRACE_DISABLED=1 python -m pytest` - - These are necessary because `app.py` initializes them in the global scope, since both Tracer and Metrics will be initialized and configured during import time. For unit tests, we could always patch and explicitly config but env vars do just fine for this example. - -# Example code - -This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. - -- hello_world - Code for the application's Lambda function. -- events - Invocation events that you can use to invoke the function. -- tests - Unit tests for the application code. -- template.yaml - A template that defines the application's AWS resources. -- requirements-dev.txt - Dev dependencies to run unit tests successfully - -The application uses several AWS resources, including Lambda functions and an API Gateway API. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. - -If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit. -The AWS Toolkit is an open source plug-in for popular IDEs that uses the SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds a simplified step-through debugging experience for Lambda function code. See the following links to get started. - -* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) -* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) -* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) -* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) - -## Deploy the sample application - -The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. - -To use the SAM CLI, you need the following tools. - -* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) -* [Python 3 installed](https://www.python.org/downloads/) -* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) - -To build and deploy your application for the first time, run the following in your shell: - -```bash -sam build --use-container -sam deploy --guided -``` - -The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts: - -* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. -* **AWS Region**: The AWS region you want to deploy your app to. -* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. -* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modified IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. If you are using `AWS::Serverless::Application` as a layer, you need also to pass `CAPABILITY_AUTO_EXPAND` during `sam deploy`, because it will create a nested stack for the layer. -* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. - -You can find your API Gateway Endpoint URL in the output values displayed after deployment. - -## Use the SAM CLI to build and test locally - -Build your application with the `sam build --use-container` command. - -```bash -example$ sam build --use-container -``` - -The SAM CLI installs dependencies defined in `hello_world/requirements.txt`, creates a deployment package, and saves it in the `.aws-sam/build` folder. - -Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. - -Run functions locally and invoke them with the `sam local invoke` command. - -```bash -example$ sam local invoke HelloWorldFunction --event events/event.json -``` - -The SAM CLI can also emulate your application's API. Use the `sam local start-api` to run the API locally on port 3000. - -```bash -example$ sam local start-api -example$ curl http://localhost:3000/ -``` - -The SAM CLI reads the application template to determine the API's routes and the functions that they invoke. The `Events` property on each function's definition includes the route and method for each path. - -```yaml - Events: - HelloWorld: - Type: Api - Properties: - Path: /hello - Method: get -``` - -## Add a resource to your application -The application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types. - -## Fetch, tail, and filter Lambda function logs - -To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. - -`NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. - -```bash -example$ sam logs -n HelloWorldFunction --stack-name example --tail -``` - -You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). - -## Unit tests - -Tests are defined in the `tests` folder in this project. Use PIP to install the deps and run unit tests. - -```bash -example$ pip install -r hello_world/requirements.txt -example$ pip install -r requirements-dev.txt -example$ pytest -v -``` - -## Cleanup - -To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: - -```bash -aws cloudformation delete-stack --stack-name example -``` - -## Resources - -See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. - -Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) diff --git a/example/events/event.json b/example/events/event.json deleted file mode 100644 index 070ad8e018c..00000000000 --- a/example/events/event.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "body": "{\"message\": \"hello world\"}", - "resource": "/{proxy+}", - "path": "/path/to/resource", - "httpMethod": "POST", - "isBase64Encoded": false, - "queryStringParameters": { - "foo": "bar" - }, - "pathParameters": { - "proxy": "/path/to/resource" - }, - "stageVariables": { - "baz": "qux" - }, - "headers": { - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", - "Accept-Encoding": "gzip, deflate, sdch", - "Accept-Language": "en-US,en;q=0.8", - "Cache-Control": "max-age=0", - "CloudFront-Forwarded-Proto": "https", - "CloudFront-Is-Desktop-Viewer": "true", - "CloudFront-Is-Mobile-Viewer": "false", - "CloudFront-Is-SmartTV-Viewer": "false", - "CloudFront-Is-Tablet-Viewer": "false", - "CloudFront-Viewer-Country": "US", - "Host": "1234567890.execute-api.us-east-1.amazonaws.com", - "Upgrade-Insecure-Requests": "1", - "User-Agent": "Custom User Agent String", - "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", - "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", - "X-Forwarded-For": "127.0.0.1, 127.0.0.2", - "X-Forwarded-Port": "443", - "X-Forwarded-Proto": "https" - }, - "requestContext": { - "accountId": "123456789012", - "resourceId": "123456", - "stage": "prod", - "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", - "requestTime": "09/Apr/2015:12:34:56 +0000", - "requestTimeEpoch": 1428582896000, - "identity": { - "cognitoIdentityPoolId": null, - "accountId": null, - "cognitoIdentityId": null, - "caller": null, - "accessKey": null, - "sourceIp": "127.0.0.1", - "cognitoAuthenticationType": null, - "cognitoAuthenticationProvider": null, - "userArn": null, - "userAgent": "Custom User Agent String", - "user": null - }, - "path": "/prod/path/to/resource", - "resourcePath": "/{proxy+}", - "httpMethod": "POST", - "apiId": "1234567890", - "protocol": "HTTP/1.1" - } -} diff --git a/example/hello_world/__init__.py b/example/hello_world/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/example/hello_world/app.py b/example/hello_world/app.py deleted file mode 100644 index 618e9a65764..00000000000 --- a/example/hello_world/app.py +++ /dev/null @@ -1,132 +0,0 @@ -import asyncio -import json - -import aioboto3 -import aiohttp -import requests - -from aws_lambda_powertools import Logger, Metrics, Tracer, single_metric -from aws_lambda_powertools.logging.logger import set_package_logger -from aws_lambda_powertools.metrics import MetricUnit -from aws_lambda_powertools.middleware_factory import lambda_handler_decorator -from aws_lambda_powertools.tracing import aiohttp_trace_config - -set_package_logger() # Enable package diagnostics (DEBUG log) - -# tracer = Tracer() # patches all available modules # noqa: E800 -tracer = Tracer(patch_modules=["aioboto3", "boto3", "requests"]) # ~90-100ms faster in perf depending on set of libs -logger = Logger() -metrics = Metrics() - -_cold_start = True - -metrics.add_dimension(name="operation", value="example") # added at cold start only - - -async def aioboto_task(): - async with aioboto3.client("sts") as sts: - account = await sts.get_caller_identity() - return account - - -async def aiohttp_task(): - # You have full access to all xray_recorder methods via `tracer.provider` - # these include thread-safe methods, all context managers, x-ray configuration etc. - # see https://github.com/aws/aws-xray-sdk-python/issues/164 - async with tracer.provider.in_subsegment_async("## aiohttp escape hatch"): - async with aiohttp.ClientSession(trace_configs=[aiohttp_trace_config()]) as session: - async with session.get("https://httpbin.org/json") as resp: - resp = await resp.json() - return resp - - -@tracer.capture_method -async def async_tasks(): - _, ret = await asyncio.gather(aioboto_task(), aiohttp_task(), return_exceptions=True) - - return {"task": "done", **ret} - - -@lambda_handler_decorator(trace_execution=True) -def my_middleware(handler, event, context, say_hello=False): - if say_hello: - print("========= HELLO PARAM DETECTED =========") - print("========= Logging event before Handler is called =========") - print(event) - ret = handler(event, context) - print("========= Logging response after Handler is called =========") - print(ret) - return ret - - -@tracer.capture_method -def func_1(): - return 1 - - -@tracer.capture_method -def func_2(): - return 2 - - -@tracer.capture_method -def sums_values(): - return func_1() + func_2() # nested sync calls to reproduce issue #32 - - -@metrics.log_metrics -@tracer.capture_lambda_handler -@my_middleware(say_hello=True) -@logger.inject_lambda_context -def lambda_handler(event, context): - """Sample pure Lambda function - - Parameters - ---------- - event: dict, required - API Gateway Lambda Proxy Input Format - - Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format # noqa: E501 - - context: object, required - Lambda Context runtime methods and attributes - - Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html - - Returns - ------ - API Gateway Lambda Proxy Output Format: dict - - Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html - """ - sums_values() - async_http_ret = asyncio.run(async_tasks()) - - if "charge_id" in event: - logger.structure_logs(append=True, payment_id="charge_id") - - global _cold_start - if _cold_start: - logger.debug("Recording cold start metric") - metrics.add_metric(name="ColdStart", unit=MetricUnit.Count, value=1) - metrics.add_dimension(name="function_name", value=context.function_name) - _cold_start = False - - try: - ip = requests.get("http://checkip.amazonaws.com/") - metrics.add_metric(name="SuccessfulLocations", unit=MetricUnit.Count, value=1) - except requests.RequestException as e: - # Send some context about this error to Lambda Logs - logger.exception(e) - raise - - with single_metric(name="UniqueMetricDimension", unit=MetricUnit.Seconds, value=1) as metric: - metric.add_dimension(name="unique_dimension", value="for_unique_metric") - - resp = {"message": "hello world", "location": ip.text.replace("\n", ""), "async_http": async_http_ret} - logger.info("Returning message to the caller") - - return { - "statusCode": 200, - "body": json.dumps(resp), - } diff --git a/example/hello_world/requirements.txt b/example/hello_world/requirements.txt deleted file mode 100644 index f89f0010c01..00000000000 --- a/example/hello_world/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -aws-lambda-powertools -requests -aioboto3 -aiohttp diff --git a/example/pytest.ini b/example/pytest.ini deleted file mode 100644 index a81cb19e53a..00000000000 --- a/example/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -addopts = -ra -v -testpaths = ./tests diff --git a/example/requirements-dev.txt b/example/requirements-dev.txt deleted file mode 100644 index 12136494321..00000000000 --- a/example/requirements-dev.txt +++ /dev/null @@ -1,2 +0,0 @@ -pytest -pytest-mock diff --git a/example/samconfig.toml b/example/samconfig.toml deleted file mode 100644 index 91e4dfe3615..00000000000 --- a/example/samconfig.toml +++ /dev/null @@ -1,9 +0,0 @@ -version = 0.1 -[default] -[default.deploy] -[default.deploy.parameters] -stack_name = "example-powertools" -s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-1pssy5gdxqcao" -s3_prefix = "example-powertools" -region = "eu-west-1" -capabilities = "CAPABILITY_IAM" diff --git a/example/template.yaml b/example/template.yaml deleted file mode 100644 index 809e981edc0..00000000000 --- a/example/template.yaml +++ /dev/null @@ -1,57 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Description: > - example - - Sample SAM Template for example - -# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst -Globals: - Function: - Timeout: 7 - -Resources: - HelloWorldFunction: - Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction - Properties: - CodeUri: hello_world/ - Handler: app.lambda_handler - Runtime: python3.8 - Layers: - - !GetAtt AwsLambdaPowertoolsPythonLayer.Outputs.LayerVersionArn - Tracing: Active # enables X-Ray tracing - Environment: - Variables: - POWERTOOLS_SERVICE_NAME: example # Sets service name used for all middlewares, "service_undefined" by default - POWERTOOLS_TRACE_DISABLED: "false" # Explicitly disables tracing, default - POWERTOOLS_LOGGER_LOG_EVENT: "false" # Logs incoming event, default - POWERTOOLS_LOGGER_SAMPLE_RATE: "0" # Debug log sampling percentage, default - POWERTOOLS_METRICS_NAMESPACE: "Example" # Metric Namespace - LOG_LEVEL: INFO # Log level for Logger (INFO, DEBUG, etc.), default - Events: - HelloWorld: - Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api - Properties: - Path: /hello - Method: get - - AwsLambdaPowertoolsPythonLayer: - Type: AWS::Serverless::Application - Properties: - Location: - ApplicationId: arn:aws:serverlessrepo:eu-west-1:057560766410:applications/aws-lambda-powertools-python-layer - SemanticVersion: 1.3.1 # change to latest semantic version available in SAR - -Outputs: - # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function - # Find out more about other implicit resources you can reference within SAM - # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api - HelloWorldApi: - Description: "API Gateway endpoint URL for Prod stage for Hello World function" - Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" - HelloWorldFunction: - Description: "Hello World Lambda Function ARN" - Value: !GetAtt HelloWorldFunction.Arn - HelloWorldFunctionIamRole: - Description: "Implicit IAM Role created for Hello World function" - Value: !GetAtt HelloWorldFunctionRole.Arn diff --git a/example/tests/__init__.py b/example/tests/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/example/tests/test_handler.py b/example/tests/test_handler.py deleted file mode 100644 index f95e1fda12c..00000000000 --- a/example/tests/test_handler.py +++ /dev/null @@ -1,117 +0,0 @@ -import json -import sys -from dataclasses import dataclass - -import pytest - -from aws_lambda_powertools import Tracer - - -@pytest.fixture(scope="function", autouse=True) -def reset_tracing_config(): - Tracer._reset_config() - yield - - -@pytest.fixture() -def env_vars(monkeypatch): - monkeypatch.setenv("POWERTOOLS_METRICS_NAMESPACE", "example_namespace") - monkeypatch.setenv("POWERTOOLS_SERVICE_NAME", "example_service") - monkeypatch.setenv("POWERTOOLS_TRACE_DISABLED", "1") - - -@pytest.fixture() -def lambda_handler(env_vars): - from hello_world import app - - return app.lambda_handler - - -@pytest.fixture() -def apigw_event(): - """ Generates API GW Event""" - - return { - "body": '{ "test": "body"}', - "resource": "/{proxy+}", - "requestContext": { - "resourceId": "123456", - "apiId": "1234567890", - "resourcePath": "/{proxy+}", - "httpMethod": "POST", - "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", - "accountId": "123456789012", - "identity": { - "apiKey": "", - "userArn": "", - "cognitoAuthenticationType": "", - "caller": "", - "userAgent": "Custom User Agent String", - "user": "", - "cognitoIdentityPoolId": "", - "cognitoIdentityId": "", - "cognitoAuthenticationProvider": "", - "sourceIp": "127.0.0.1", - "accountId": "", - }, - "stage": "prod", - }, - "queryStringParameters": {"foo": "bar"}, - "headers": { - "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", - "Accept-Language": "en-US,en;q=0.8", - "CloudFront-Is-Desktop-Viewer": "true", - "CloudFront-Is-SmartTV-Viewer": "false", - "CloudFront-Is-Mobile-Viewer": "false", - "X-Forwarded-For": "127.0.0.1, 127.0.0.2", - "CloudFront-Viewer-Country": "US", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", - "Upgrade-Insecure-Requests": "1", - "X-Forwarded-Port": "443", - "Host": "1234567890.execute-api.us-east-1.amazonaws.com", - "X-Forwarded-Proto": "https", - "X-Amz-Cf-Id": "aaaaaaaaaae3VYQb9jd-nvCd-de396Uhbp027Y2JvkCPNLmGJHqlaA==", - "CloudFront-Is-Tablet-Viewer": "false", - "Cache-Control": "max-age=0", - "User-Agent": "Custom User Agent String", - "CloudFront-Forwarded-Proto": "https", - "Accept-Encoding": "gzip, deflate, sdch", - }, - "pathParameters": {"proxy": "/examplepath"}, - "httpMethod": "POST", - "stageVariables": {"baz": "qux"}, - "path": "/examplepath", - } - - -@dataclass -class Context: - function_name: str = "test" - memory_limit_in_mb: int = 128 - invoked_function_arn: str = "arn:aws:lambda:eu-west-1:298026489:function:test" - aws_request_id: str = "5b441b59-a550-11c8-6564-f1c833cf438c" - - -@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher") -def test_lambda_handler(lambda_handler, apigw_event, mocker, capsys): - ret = lambda_handler(apigw_event, Context()) - data = json.loads(ret["body"]) - - output = capsys.readouterr() - output = output.out.split("\n") - stdout_one_string = "\t".join(output) - - assert ret["statusCode"] == 200 - assert data["message"] == "hello world" - assert "location" in data - assert "message" in ret["body"] - assert "async_http" in data - - # assess custom metric was flushed in stdout/logs - assert "SuccessfulLocations" in stdout_one_string - assert "ColdStart" in stdout_one_string - assert "UniqueMetricDimension" in stdout_one_string - - # assess our custom middleware ran - assert "Logging response after Handler is called" in stdout_one_string - assert "Logging event before Handler is called" in stdout_one_string diff --git a/pytest.ini b/pytest.ini index 8797d0bbab9..45345cbd365 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,3 +1,3 @@ [pytest] addopts = -ra --cov --cov-config=.coveragerc -testpaths = ./tests ./example/tests +testpaths = ./tests From f1d39e132c49f0163a78a768c34d94a8371a2eb5 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 25 Sep 2020 13:13:50 +0200 Subject: [PATCH 12/14] chore: remove dev deps from example project --- poetry.lock | 412 ++++++++++--------------------------------------- pyproject.toml | 3 - 2 files changed, 82 insertions(+), 333 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3468eca5eb0..f1917844a4f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,78 +1,3 @@ -[[package]] -category = "dev" -description = "Async boto3 wrapper" -name = "aioboto3" -optional = false -python-versions = ">=3.6" -version = "8.0.5" - -[package.dependencies] -[package.dependencies.aiobotocore] -extras = ["boto3"] -version = "1.0.4" - -[package.extras] -s3cse = ["cryptography (>=2.3.1)"] - -[[package]] -category = "dev" -description = "Async client for aws services using botocore and aiohttp" -name = "aiobotocore" -optional = false -python-versions = ">=3.6" -version = "1.0.4" - -[package.dependencies] -aiohttp = ">=3.3.1" -aioitertools = ">=0.5.1" -botocore = ">=1.15.32,<1.15.33" -wrapt = ">=1.10.10" - -[package.dependencies.boto3] -optional = true -version = "1.12.32" - -[package.extras] -awscli = ["awscli (1.18.32)"] -boto3 = ["boto3 (1.12.32)"] - -[[package]] -category = "dev" -description = "Async http client/server framework (asyncio)" -name = "aiohttp" -optional = false -python-versions = ">=3.5.3" -version = "3.6.2" - -[package.dependencies] -async-timeout = ">=3.0,<4.0" -attrs = ">=17.3.0" -chardet = ">=2.0,<4.0" -multidict = ">=4.5,<5.0" -yarl = ">=1.0,<2.0" - -[package.dependencies.idna-ssl] -python = "<3.7" -version = ">=1.0" - -[package.dependencies.typing-extensions] -python = "<3.7" -version = ">=3.6.5" - -[package.extras] -speedups = ["aiodns", "brotlipy", "cchardet"] - -[[package]] -category = "dev" -description = "itertools and builtins for AsyncIO and mixed iterables" -name = "aioitertools" -optional = false -python-versions = ">=3.6" -version = "0.7.0" - -[package.dependencies] -typing_extensions = ">=3.7" - [[package]] category = "dev" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." @@ -81,14 +6,6 @@ optional = false python-versions = "*" version = "1.4.4" -[[package]] -category = "dev" -description = "Timeout context manager for asyncio programs" -name = "async-timeout" -optional = false -python-versions = ">=3.5.3" -version = "3.0.1" - [[package]] category = "dev" description = "Atomic file writes." @@ -104,13 +21,12 @@ description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.2.0" +version = "20.1.0" [package.extras] dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] category = "main" @@ -230,7 +146,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.3" +version = "5.2.1" [package.dependencies] [package.dependencies.toml] @@ -240,15 +156,6 @@ version = "*" [package.extras] toml = ["toml"] -[[package]] -category = "dev" -description = "A backport of the dataclasses module for Python 3.6" -marker = "python_version >= \"3.6\" and python_version < \"3.7\" or python_version < \"3.7\"" -name = "dataclasses" -optional = false -python-versions = ">=3.6, <3.7" -version = "0.7" - [[package]] category = "main" description = "Docutils -- Python Documentation Utilities" @@ -398,6 +305,17 @@ version = ">=4.3.5" [package.extras] test = ["pytest"] +[[package]] +category = "dev" +description = "Polyfill package for Flake8 plugins" +name = "flake8-polyfill" +optional = false +python-versions = "*" +version = "1.0.2" + +[package.dependencies] +flake8 = "*" + [[package]] category = "dev" description = "A flake8 extension that helps to make more readable variables names" @@ -434,7 +352,7 @@ description = "Python Git Library" name = "gitpython" optional = false python-versions = ">=3.4" -version = "3.1.8" +version = "3.1.7" [package.dependencies] gitdb = ">=4.0.1,<5" @@ -447,25 +365,13 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.10" -[[package]] -category = "dev" -description = "Patch ssl.match_hostname for Unicode(idna) domains support" -marker = "python_version < \"3.7\"" -name = "idna-ssl" -optional = false -python-versions = "*" -version = "1.1.0" - -[package.dependencies] -idna = ">=2.0" - [[package]] category = "main" description = "Read metadata from Python packages" name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "2.0.0" +version = "1.7.0" [package.dependencies] zipp = ">=0.5" @@ -581,14 +487,6 @@ optional = false python-versions = ">=3.5" version = "8.5.0" -[[package]] -category = "dev" -description = "multidict implementation" -name = "multidict" -optional = false -python-versions = ">=3.5" -version = "4.7.6" - [[package]] category = "dev" description = "Core utilities for Python packages" @@ -614,8 +512,8 @@ category = "dev" description = "Python Build Reasonableness" name = "pbr" optional = false -python-versions = ">=2.6" -version = "5.5.0" +python-versions = "*" +version = "5.4.5" [[package]] category = "dev" @@ -661,24 +559,6 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.6.0" -[[package]] -category = "dev" -description = "Data validation and settings management using python 3.6 type hinting" -name = "pydantic" -optional = true -python-versions = ">=3.6" -version = "1.6.1" - -[package.dependencies] -[package.dependencies.dataclasses] -python = "<3.7" -version = ">=0.6" - -[package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] -typing_extensions = ["typing-extensions (>=3.7.2)"] - [[package]] category = "dev" description = "passive checker of Python programs" @@ -789,9 +669,10 @@ description = "Code Metrics in Python" name = "radon" optional = false python-versions = "*" -version = "4.3.2" +version = "4.2.0" [package.dependencies] +flake8-polyfill = "*" future = "*" mando = ">=0.6,<0.7" @@ -799,9 +680,6 @@ mando = ">=0.6,<0.7" python = ">=3.5" version = ">=0.4.1" -[package.extras] -flake8 = ["flake8-polyfill"] - [[package]] category = "dev" description = "Alternative regular expression module, to replace re." @@ -861,7 +739,7 @@ description = "Manage dynamic plugins for Python applications" name = "stevedore" optional = false python-versions = ">=3.6" -version = "3.2.2" +version = "3.2.0" [package.dependencies] pbr = ">=2.0.0,<2.1.0 || >2.1.0" @@ -876,7 +754,7 @@ description = "A collection of helpers and mock objects for unit tests and doc t name = "testfixtures" optional = false python-versions = "*" -version = "6.14.2" +version = "6.14.1" [package.extras] build = ["setuptools-git", "wheel", "twine"] @@ -899,14 +777,6 @@ optional = false python-versions = "*" version = "1.4.1" -[[package]] -category = "dev" -description = "Backported and Experimental Type Hints for Python 3.5+" -name = "typing-extensions" -optional = false -python-versions = "*" -version = "3.7.4.3" - [[package]] category = "main" description = "HTTP library with thread-safe connection pooling, file post, and more." @@ -942,95 +812,42 @@ description = "Monitor code metrics for Python on your CI server" name = "xenon" optional = false python-versions = "*" -version = "0.7.1" +version = "0.7.0" [package.dependencies] PyYAML = ">=4.2b1,<6.0" +radon = ">=4,<5" requests = ">=2.0,<3.0" -[package.dependencies.radon] -extras = ["flake8"] -version = ">=4,<5" - -[[package]] -category = "dev" -description = "Yet another URL library" -name = "yarl" -optional = false -python-versions = ">=3.5" -version = "1.6.0" - -[package.dependencies] -idna = ">=2.0" -multidict = ">=4.0" - -[package.dependencies.typing-extensions] -python = "<3.8" -version = ">=3.7.4" - [[package]] category = "main" description = "Backport of pathlib-compatible object wrapper for zip files" -marker = "python_version < \"3.8\"" name = "zipp" optional = false python-versions = ">=3.6" -version = "3.2.0" +version = "3.1.0" [package.extras] docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] - -[extras] -advanced_parser = [] +testing = ["jaraco.itertools", "func-timeout"] [metadata] -content-hash = "0b2af58f51056899a11bae6af87144603bd653c65aa4db03d3517fff654a6047" +content-hash = "a2036c75a7509f15f2273d2d907fa4d1418f56e76a948994ae01ce0e26a0175a" lock-version = "1.0" python-versions = "^3.6" [metadata.files] -aioboto3 = [ - {file = "aioboto3-8.0.5-py2.py3-none-any.whl", hash = "sha256:909e01ad05c43c0fc5c0d3e1e1f795377c2d0091bc37d969bf2cbc46ee4545ba"}, - {file = "aioboto3-8.0.5.tar.gz", hash = "sha256:0942ca5feff0b95b96a79ba93a70042daf9304015f15f489801709173796c486"}, -] -aiobotocore = [ - {file = "aiobotocore-1.0.4-py3-none-any.whl", hash = "sha256:1e89ef97c52eb77d89c7c4a9130cab162ae3b89d2709c6e45da30824163ed8d3"}, - {file = "aiobotocore-1.0.4.tar.gz", hash = "sha256:4103d90b9e162176203dc5295124b15f56c37eee0ddbcddc6929760443714ff8"}, -] -aiohttp = [ - {file = "aiohttp-3.6.2-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:1e984191d1ec186881ffaed4581092ba04f7c61582a177b187d3a2f07ed9719e"}, - {file = "aiohttp-3.6.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:50aaad128e6ac62e7bf7bd1f0c0a24bc968a0c0590a726d5a955af193544bcec"}, - {file = "aiohttp-3.6.2-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:65f31b622af739a802ca6fd1a3076fd0ae523f8485c52924a89561ba10c49b48"}, - {file = "aiohttp-3.6.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ae55bac364c405caa23a4f2d6cfecc6a0daada500274ffca4a9230e7129eac59"}, - {file = "aiohttp-3.6.2-cp36-cp36m-win32.whl", hash = "sha256:344c780466b73095a72c616fac5ea9c4665add7fc129f285fbdbca3cccf4612a"}, - {file = "aiohttp-3.6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:4c6efd824d44ae697814a2a85604d8e992b875462c6655da161ff18fd4f29f17"}, - {file = "aiohttp-3.6.2-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:2f4d1a4fdce595c947162333353d4a44952a724fba9ca3205a3df99a33d1307a"}, - {file = "aiohttp-3.6.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6206a135d072f88da3e71cc501c59d5abffa9d0bb43269a6dcd28d66bfafdbdd"}, - {file = "aiohttp-3.6.2-cp37-cp37m-win32.whl", hash = "sha256:b778ce0c909a2653741cb4b1ac7015b5c130ab9c897611df43ae6a58523cb965"}, - {file = "aiohttp-3.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:32e5f3b7e511aa850829fbe5aa32eb455e5534eaa4b1ce93231d00e2f76e5654"}, - {file = "aiohttp-3.6.2-py3-none-any.whl", hash = "sha256:460bd4237d2dbecc3b5ed57e122992f60188afe46e7319116da5eb8a9dfedba4"}, - {file = "aiohttp-3.6.2.tar.gz", hash = "sha256:259ab809ff0727d0e834ac5e8a283dc5e3e0ecc30c4d80b3cd17a4139ce1f326"}, -] -aioitertools = [ - {file = "aioitertools-0.7.0-py3-none-any.whl", hash = "sha256:e931a2f0dcabd4a8446b5cc2fc71b8bb14716e6adf37728a70869213f1f741cd"}, - {file = "aioitertools-0.7.0.tar.gz", hash = "sha256:341cb05a0903177ef1b73d4cc12c92aee18e81c364e0138f4efc7ec3c47b8177"}, -] appdirs = [ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] -async-timeout = [ - {file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"}, - {file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"}, -] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, - {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, + {file = "attrs-20.1.0-py2.py3-none-any.whl", hash = "sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff"}, + {file = "attrs-20.1.0.tar.gz", hash = "sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a"}, ] aws-xray-sdk = [ {file = "aws-xray-sdk-2.6.0.tar.gz", hash = "sha256:abf5b90f740e1f402e23414c9670e59cb9772e235e271fef2bce62b9100cbc77"}, @@ -1069,44 +886,40 @@ colorama = [ {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, ] coverage = [ - {file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"}, - {file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"}, - {file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"}, - {file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"}, - {file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"}, - {file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"}, - {file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"}, - {file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"}, - {file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"}, - {file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"}, - {file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"}, - {file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"}, - {file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"}, - {file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"}, - {file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"}, - {file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"}, - {file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"}, - {file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"}, - {file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"}, - {file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"}, - {file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"}, - {file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"}, - {file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"}, - {file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"}, - {file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"}, - {file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"}, - {file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"}, - {file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"}, - {file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"}, - {file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"}, - {file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"}, - {file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"}, - {file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"}, - {file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"}, -] -dataclasses = [ - {file = "dataclasses-0.7-py3-none-any.whl", hash = "sha256:3459118f7ede7c8bea0fe795bff7c6c2ce287d01dd226202f7c9ebc0610a7836"}, - {file = "dataclasses-0.7.tar.gz", hash = "sha256:494a6dcae3b8bcf80848eea2ef64c0cc5cd307ffc263e17cdf42f3e5420808e6"}, + {file = "coverage-5.2.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:40f70f81be4d34f8d491e55936904db5c527b0711b2a46513641a5729783c2e4"}, + {file = "coverage-5.2.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:675192fca634f0df69af3493a48224f211f8db4e84452b08d5fcebb9167adb01"}, + {file = "coverage-5.2.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2fcc8b58953d74d199a1a4d633df8146f0ac36c4e720b4a1997e9b6327af43a8"}, + {file = "coverage-5.2.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:64c4f340338c68c463f1b56e3f2f0423f7b17ba6c3febae80b81f0e093077f59"}, + {file = "coverage-5.2.1-cp27-cp27m-win32.whl", hash = "sha256:52f185ffd3291196dc1aae506b42e178a592b0b60a8610b108e6ad892cfc1bb3"}, + {file = "coverage-5.2.1-cp27-cp27m-win_amd64.whl", hash = "sha256:30bc103587e0d3df9e52cd9da1dd915265a22fad0b72afe54daf840c984b564f"}, + {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9ea749fd447ce7fb1ac71f7616371f04054d969d412d37611716721931e36efd"}, + {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ce7866f29d3025b5b34c2e944e66ebef0d92e4a4f2463f7266daa03a1332a651"}, + {file = "coverage-5.2.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:4869ab1c1ed33953bb2433ce7b894a28d724b7aa76c19b11e2878034a4e4680b"}, + {file = "coverage-5.2.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a3ee9c793ffefe2944d3a2bd928a0e436cd0ac2d9e3723152d6fd5398838ce7d"}, + {file = "coverage-5.2.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28f42dc5172ebdc32622a2c3f7ead1b836cdbf253569ae5673f499e35db0bac3"}, + {file = "coverage-5.2.1-cp35-cp35m-win32.whl", hash = "sha256:e26c993bd4b220429d4ec8c1468eca445a4064a61c74ca08da7429af9bc53bb0"}, + {file = "coverage-5.2.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4186fc95c9febeab5681bc3248553d5ec8c2999b8424d4fc3a39c9cba5796962"}, + {file = "coverage-5.2.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:b360d8fd88d2bad01cb953d81fd2edd4be539df7bfec41e8753fe9f4456a5082"}, + {file = "coverage-5.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1adb6be0dcef0cf9434619d3b892772fdb48e793300f9d762e480e043bd8e716"}, + {file = "coverage-5.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:098a703d913be6fbd146a8c50cc76513d726b022d170e5e98dc56d958fd592fb"}, + {file = "coverage-5.2.1-cp36-cp36m-win32.whl", hash = "sha256:962c44070c281d86398aeb8f64e1bf37816a4dfc6f4c0f114756b14fc575621d"}, + {file = "coverage-5.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1ed2bdb27b4c9fc87058a1cb751c4df8752002143ed393899edb82b131e0546"}, + {file = "coverage-5.2.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:c890728a93fffd0407d7d37c1e6083ff3f9f211c83b4316fae3778417eab9811"}, + {file = "coverage-5.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:538f2fd5eb64366f37c97fdb3077d665fa946d2b6d95447622292f38407f9258"}, + {file = "coverage-5.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:27ca5a2bc04d68f0776f2cdcb8bbd508bbe430a7bf9c02315cd05fb1d86d0034"}, + {file = "coverage-5.2.1-cp37-cp37m-win32.whl", hash = "sha256:aab75d99f3f2874733946a7648ce87a50019eb90baef931698f96b76b6769a46"}, + {file = "coverage-5.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:c2ff24df02a125b7b346c4c9078c8936da06964cc2d276292c357d64378158f8"}, + {file = "coverage-5.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:304fbe451698373dc6653772c72c5d5e883a4aadaf20343592a7abb2e643dae0"}, + {file = "coverage-5.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c96472b8ca5dc135fb0aa62f79b033f02aa434fb03a8b190600a5ae4102df1fd"}, + {file = "coverage-5.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8505e614c983834239f865da2dd336dcf9d72776b951d5dfa5ac36b987726e1b"}, + {file = "coverage-5.2.1-cp38-cp38-win32.whl", hash = "sha256:700997b77cfab016533b3e7dbc03b71d33ee4df1d79f2463a318ca0263fc29dd"}, + {file = "coverage-5.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:46794c815e56f1431c66d81943fa90721bb858375fb36e5903697d5eef88627d"}, + {file = "coverage-5.2.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:16042dc7f8e632e0dcd5206a5095ebd18cb1d005f4c89694f7f8aafd96dd43a3"}, + {file = "coverage-5.2.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c1bbb628ed5192124889b51204de27c575b3ffc05a5a91307e7640eff1d48da4"}, + {file = "coverage-5.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4f6428b55d2916a69f8d6453e48a505c07b2245653b0aa9f0dee38785939f5e4"}, + {file = "coverage-5.2.1-cp39-cp39-win32.whl", hash = "sha256:9e536783a5acee79a9b308be97d3952b662748c4037b6a24cbb339dc7ed8eb89"}, + {file = "coverage-5.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b"}, + {file = "coverage-5.2.1.tar.gz", hash = "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b"}, ] docutils = [ {file = "docutils-0.15.2-py2-none-any.whl", hash = "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827"}, @@ -1154,6 +967,10 @@ flake8-isort = [ {file = "flake8-isort-2.9.1.tar.gz", hash = "sha256:0d34b266080e1748412b203a1690792245011706b1858c203476b43460bf3652"}, {file = "flake8_isort-2.9.1-py2.py3-none-any.whl", hash = "sha256:a77df28778a1ac6ac4153339ebd9d252935f3ed4379872d4f8b84986296d8cc3"}, ] +flake8-polyfill = [ + {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, + {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, +] flake8-variables-names = [ {file = "flake8_variables_names-0.0.3.tar.gz", hash = "sha256:d109f5a8fe8c20d64e165287330f1b0160b442d7f96e1527124ba1b63c438347"}, ] @@ -1165,19 +982,16 @@ gitdb = [ {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, ] gitpython = [ - {file = "GitPython-3.1.8-py3-none-any.whl", hash = "sha256:1858f4fd089abe92ae465f01d5aaaf55e937eca565fb2c1fce35a51b5f85c910"}, - {file = "GitPython-3.1.8.tar.gz", hash = "sha256:080bf8e2cf1a2b907634761c2eaefbe83b69930c94c66ad11b65a8252959f912"}, + {file = "GitPython-3.1.7-py3-none-any.whl", hash = "sha256:fa3b92da728a457dd75d62bb5f3eb2816d99a7fe6c67398e260637a40e3fafb5"}, + {file = "GitPython-3.1.7.tar.gz", hash = "sha256:2db287d71a284e22e5c2846042d0602465c7434d910406990d5b74df4afb0858"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] -idna-ssl = [ - {file = "idna-ssl-1.1.0.tar.gz", hash = "sha256:a933e3bb13da54383f9e8f35dc4f9cb9eb9b3b78c6b36f311254d6d0d92c6c7c"}, -] importlib-metadata = [ - {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"}, - {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"}, + {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, + {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, ] isort = [ {file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"}, @@ -1246,25 +1060,6 @@ more-itertools = [ {file = "more-itertools-8.5.0.tar.gz", hash = "sha256:6f83822ae94818eae2612063a5101a7311e68ae8002005b5e05f03fd74a86a20"}, {file = "more_itertools-8.5.0-py3-none-any.whl", hash = "sha256:9b30f12df9393f0d28af9210ff8efe48d10c94f73e5daf886f10c4b0b0b4f03c"}, ] -multidict = [ - {file = "multidict-4.7.6-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:275ca32383bc5d1894b6975bb4ca6a7ff16ab76fa622967625baeebcf8079000"}, - {file = "multidict-4.7.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1ece5a3369835c20ed57adadc663400b5525904e53bae59ec854a5d36b39b21a"}, - {file = "multidict-4.7.6-cp35-cp35m-win32.whl", hash = "sha256:5141c13374e6b25fe6bf092052ab55c0c03d21bd66c94a0e3ae371d3e4d865a5"}, - {file = "multidict-4.7.6-cp35-cp35m-win_amd64.whl", hash = "sha256:9456e90649005ad40558f4cf51dbb842e32807df75146c6d940b6f5abb4a78f3"}, - {file = "multidict-4.7.6-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:e0d072ae0f2a179c375f67e3da300b47e1a83293c554450b29c900e50afaae87"}, - {file = "multidict-4.7.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3750f2205b800aac4bb03b5ae48025a64e474d2c6cc79547988ba1d4122a09e2"}, - {file = "multidict-4.7.6-cp36-cp36m-win32.whl", hash = "sha256:f07acae137b71af3bb548bd8da720956a3bc9f9a0b87733e0899226a2317aeb7"}, - {file = "multidict-4.7.6-cp36-cp36m-win_amd64.whl", hash = "sha256:6513728873f4326999429a8b00fc7ceddb2509b01d5fd3f3be7881a257b8d463"}, - {file = "multidict-4.7.6-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:feed85993dbdb1dbc29102f50bca65bdc68f2c0c8d352468c25b54874f23c39d"}, - {file = "multidict-4.7.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fcfbb44c59af3f8ea984de67ec7c306f618a3ec771c2843804069917a8f2e255"}, - {file = "multidict-4.7.6-cp37-cp37m-win32.whl", hash = "sha256:4538273208e7294b2659b1602490f4ed3ab1c8cf9dbdd817e0e9db8e64be2507"}, - {file = "multidict-4.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:d14842362ed4cf63751648e7672f7174c9818459d169231d03c56e84daf90b7c"}, - {file = "multidict-4.7.6-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:c026fe9a05130e44157b98fea3ab12969e5b60691a276150db9eda71710cd10b"}, - {file = "multidict-4.7.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:51a4d210404ac61d32dada00a50ea7ba412e6ea945bbe992e4d7a595276d2ec7"}, - {file = "multidict-4.7.6-cp38-cp38-win32.whl", hash = "sha256:5cf311a0f5ef80fe73e4f4c0f0998ec08f954a6ec72b746f3c179e37de1d210d"}, - {file = "multidict-4.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:7388d2ef3c55a8ba80da62ecfafa06a1c097c18032a501ffd4cabbc52d7f2b19"}, - {file = "multidict-4.7.6.tar.gz", hash = "sha256:fbb77a75e529021e7c4a8d4e823d88ef4d23674a202be4f5addffc72cbb91430"}, -] packaging = [ {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, @@ -1274,8 +1069,8 @@ pathspec = [ {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, ] pbr = [ - {file = "pbr-5.5.0-py2.py3-none-any.whl", hash = "sha256:5adc0f9fc64319d8df5ca1e4e06eea674c26b80e6f00c530b18ce6a6592ead15"}, - {file = "pbr-5.5.0.tar.gz", hash = "sha256:14bfd98f51c78a3dd22a1ef45cf194ad79eee4a19e8e1a0d5c7f8e81ffe182ea"}, + {file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"}, + {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"}, ] pdoc3 = [ {file = "pdoc3-0.7.5.tar.gz", hash = "sha256:ebca75b7fcf23f3b4320abe23339834d3f08c28517718e9d29e555fc38eeb33c"}, @@ -1292,25 +1087,6 @@ pycodestyle = [ {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, ] -pydantic = [ - {file = "pydantic-1.6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:418b84654b60e44c0cdd5384294b0e4bc1ebf42d6e873819424f3b78b8690614"}, - {file = "pydantic-1.6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4900b8820b687c9a3ed753684337979574df20e6ebe4227381d04b3c3c628f99"}, - {file = "pydantic-1.6.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b49c86aecde15cde33835d5d6360e55f5e0067bb7143a8303bf03b872935c75b"}, - {file = "pydantic-1.6.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2de562a456c4ecdc80cf1a8c3e70c666625f7d02d89a6174ecf63754c734592e"}, - {file = "pydantic-1.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f769141ab0abfadf3305d4fcf36660e5cf568a666dd3efab7c3d4782f70946b1"}, - {file = "pydantic-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2dc946b07cf24bee4737ced0ae77e2ea6bc97489ba5a035b603bd1b40ad81f7e"}, - {file = "pydantic-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:36dbf6f1be212ab37b5fda07667461a9219c956181aa5570a00edfb0acdfe4a1"}, - {file = "pydantic-1.6.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:1783c1d927f9e1366e0e0609ae324039b2479a1a282a98ed6a6836c9ed02002c"}, - {file = "pydantic-1.6.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:cf3933c98cb5e808b62fae509f74f209730b180b1e3c3954ee3f7949e083a7df"}, - {file = "pydantic-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f8af9b840a9074e08c0e6dc93101de84ba95df89b267bf7151d74c553d66833b"}, - {file = "pydantic-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:40d765fa2d31d5be8e29c1794657ad46f5ee583a565c83cea56630d3ae5878b9"}, - {file = "pydantic-1.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3fa799f3cfff3e5f536cbd389368fc96a44bb30308f258c94ee76b73bd60531d"}, - {file = "pydantic-1.6.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:6c3f162ba175678218629f446a947e3356415b6b09122dcb364e58c442c645a7"}, - {file = "pydantic-1.6.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:eb75dc1809875d5738df14b6566ccf9fd9c0bcde4f36b72870f318f16b9f5c20"}, - {file = "pydantic-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:530d7222a2786a97bc59ee0e0ebbe23728f82974b1f1ad9a11cd966143410633"}, - {file = "pydantic-1.6.1-py36.py37.py38-none-any.whl", hash = "sha256:b5b3489cb303d0f41ad4a7390cf606a5f2c7a94dcba20c051cd1c653694cb14d"}, - {file = "pydantic-1.6.1.tar.gz", hash = "sha256:54122a8ed6b75fe1dd80797f8251ad2063ea348a03b77218d73ea9fe19bd4e73"}, -] pyflakes = [ {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, @@ -1352,8 +1128,8 @@ pyyaml = [ {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, ] radon = [ - {file = "radon-4.3.2-py2.py3-none-any.whl", hash = "sha256:b991de491eb2edbc2aac8f5f7ebf02b799852f076fa5a73fedf79d144d85e37e"}, - {file = "radon-4.3.2.tar.gz", hash = "sha256:758b3ab345aa86e95f642713612a57da7c7da6d552c4dbfbe397a67601ace7dd"}, + {file = "radon-4.2.0-py2.py3-none-any.whl", hash = "sha256:215e42c8748b5ca8ddf7c061831600b9e73e9c48770a81eeaaeeb066697aee15"}, + {file = "radon-4.2.0.tar.gz", hash = "sha256:b73f6f469c15c9616e0f7ce12080a9ecdee9f2335bdbb5ccea1f2bae26e8d20d"}, ] regex = [ {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"}, @@ -1395,12 +1171,12 @@ smmap = [ {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, ] stevedore = [ - {file = "stevedore-3.2.2-py3-none-any.whl", hash = "sha256:5e1ab03eaae06ef6ce23859402de785f08d97780ed774948ef16c4652c41bc62"}, - {file = "stevedore-3.2.2.tar.gz", hash = "sha256:f845868b3a3a77a2489d226568abe7328b5c2d4f6a011cc759dfa99144a521f0"}, + {file = "stevedore-3.2.0-py3-none-any.whl", hash = "sha256:c8f4f0ebbc394e52ddf49de8bcc3cf8ad2b4425ebac494106bbc5e3661ac7633"}, + {file = "stevedore-3.2.0.tar.gz", hash = "sha256:38791aa5bed922b0a844513c5f9ed37774b68edc609e5ab8ab8d8fe0ce4315e5"}, ] testfixtures = [ - {file = "testfixtures-6.14.2-py2.py3-none-any.whl", hash = "sha256:816557888877f498081c1b5c572049b4a2ddffedb77401308ff4cdc1bb9147b7"}, - {file = "testfixtures-6.14.2.tar.gz", hash = "sha256:14d9907390f5f9c7189b3d511b64f34f1072d07cc13b604a57e1bb79029376e3"}, + {file = "testfixtures-6.14.1-py2.py3-none-any.whl", hash = "sha256:30566e24a1b34e4d3f8c13abf62557d01eeb4480bcb8f1745467bfb0d415a7d9"}, + {file = "testfixtures-6.14.1.tar.gz", hash = "sha256:58d2b3146d93bc5ddb0cd24e0ccacb13e29bdb61e5c81235c58f7b8ee4470366"}, ] toml = [ {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, @@ -1429,11 +1205,6 @@ typed-ast = [ {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, ] -typing-extensions = [ - {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, - {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, - {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, -] urllib3 = [ {file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"}, {file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"}, @@ -1446,29 +1217,10 @@ wrapt = [ {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] xenon = [ - {file = "xenon-0.7.1-py2.py3-none-any.whl", hash = "sha256:33d807ef805a2ed854adfcc7cc998398d5c0626a5ad443e52684b998a4dd4aa3"}, - {file = "xenon-0.7.1.tar.gz", hash = "sha256:38bf283135f0636355ecf6054b6f37226af12faab152161bda1a4f9e4dc5b701"}, -] -yarl = [ - {file = "yarl-1.6.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:db9eb8307219d7e09b33bcb43287222ef35cbcf1586ba9472b0a4b833666ada1"}, - {file = "yarl-1.6.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:e31fef4e7b68184545c3d68baec7074532e077bd1906b040ecfba659737df188"}, - {file = "yarl-1.6.0-cp35-cp35m-win32.whl", hash = "sha256:5d84cc36981eb5a8533be79d6c43454c8e6a39ee3118ceaadbd3c029ab2ee580"}, - {file = "yarl-1.6.0-cp35-cp35m-win_amd64.whl", hash = "sha256:5e447e7f3780f44f890360ea973418025e8c0cdcd7d6a1b221d952600fd945dc"}, - {file = "yarl-1.6.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:6f6898429ec3c4cfbef12907047136fd7b9e81a6ee9f105b45505e633427330a"}, - {file = "yarl-1.6.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d088ea9319e49273f25b1c96a3763bf19a882cff774d1792ae6fba34bd40550a"}, - {file = "yarl-1.6.0-cp36-cp36m-win32.whl", hash = "sha256:b7c199d2cbaf892ba0f91ed36d12ff41ecd0dde46cbf64ff4bfe997a3ebc925e"}, - {file = "yarl-1.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:67c5ea0970da882eaf9efcf65b66792557c526f8e55f752194eff8ec722c75c2"}, - {file = "yarl-1.6.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:04a54f126a0732af75e5edc9addeaa2113e2ca7c6fce8974a63549a70a25e50e"}, - {file = "yarl-1.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fcbe419805c9b20db9a51d33b942feddbf6e7fb468cb20686fd7089d4164c12a"}, - {file = "yarl-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:c604998ab8115db802cc55cb1b91619b2831a6128a62ca7eea577fc8ea4d3131"}, - {file = "yarl-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c22607421f49c0cb6ff3ed593a49b6a99c6ffdeaaa6c944cdda83c2393c8864d"}, - {file = "yarl-1.6.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:7ce35944e8e61927a8f4eb78f5bc5d1e6da6d40eadd77e3f79d4e9399e263921"}, - {file = "yarl-1.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c15d71a640fb1f8e98a1423f9c64d7f1f6a3a168f803042eaf3a5b5022fde0c1"}, - {file = "yarl-1.6.0-cp38-cp38-win32.whl", hash = "sha256:3cc860d72ed989f3b1f3abbd6ecf38e412de722fb38b8f1b1a086315cf0d69c5"}, - {file = "yarl-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:e32f0fb443afcfe7f01f95172b66f279938fbc6bdaebe294b0ff6747fb6db020"}, - {file = "yarl-1.6.0.tar.gz", hash = "sha256:61d3ea3c175fe45f1498af868879c6ffeb989d4143ac542163c45538ba5ec21b"}, + {file = "xenon-0.7.0-py2.py3-none-any.whl", hash = "sha256:83e98f67b7077c95c25c3402aea6203dd2ed6256708b76ed9751e9dbf1aba125"}, + {file = "xenon-0.7.0.tar.gz", hash = "sha256:5e6433c9297d965bf666256a0a030b6e13660ab87680220c4eb07241f101625b"}, ] zipp = [ - {file = "zipp-3.2.0-py3-none-any.whl", hash = "sha256:43f4fa8d8bb313e65d8323a3952ef8756bf40f9a5c3ea7334be23ee4ec8278b6"}, - {file = "zipp-3.2.0.tar.gz", hash = "sha256:b52f22895f4cfce194bc8172f3819ee8de7540aa6d873535a8668b730b8b411f"}, + {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, + {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, ] diff --git a/pyproject.toml b/pyproject.toml index fe46046fb5e..d6c3f6e6022 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,13 +41,10 @@ pytest-cov = "^2.8.1" pytest-mock = "^2.0.0" pdoc3 = "^0.7.5" pytest-asyncio = "^0.12.0" -aioboto3 = "^8.0.3" -aiohttp = "^3.6.2" bandit = "^1.6.2" radon = "^4.1.0" xenon = "^0.7.0" flake8-eradicate = "^0.3.0" -dataclasses = {version = "*", python = "~3.6"} flake8-bugbear = "^20.1.4" pydantic = {version = "^1.6.0", optional = true } From 38e1582c41589af4a20e3502b7b07ead60942de9 Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Fri, 25 Sep 2020 19:53:02 +0300 Subject: [PATCH 13/14] fix: poetry update + pydantic, typing_extensions as optional --- Makefile | 2 +- .../advanced_parser/schemas/dynamodb.py | 1 + .../utilities/advanced_parser/schemas/sqs.py | 1 + poetry.lock | 229 +++++++++++------- pyproject.toml | 6 +- tests/functional/parser/schemas.py | 2 +- 6 files changed, 152 insertions(+), 89 deletions(-) diff --git a/Makefile b/Makefile index 19d77a0b508..aa461af123d 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ target: dev: pip install --upgrade pip poetry pre-commit poetry install - poetry install --extras "advanced_parser" + poetry install --extras "pydantic" pre-commit install dev-docs: diff --git a/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py index 484d25cc7b7..94c24f3313c 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py +++ b/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py @@ -2,6 +2,7 @@ from typing import Any, Dict, List, Optional from pydantic import BaseModel, root_validator + from typing_extensions import Literal diff --git a/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py index d4b3c09ddd6..416d26a6d54 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py +++ b/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py @@ -3,6 +3,7 @@ from typing import Dict, List, Optional from pydantic import BaseModel, root_validator, validator + from typing_extensions import Literal diff --git a/poetry.lock b/poetry.lock index f1917844a4f..94bf8b20b7c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -21,12 +21,13 @@ description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.1.0" +version = "20.2.0" [package.extras] dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] category = "main" @@ -83,10 +84,10 @@ description = "The AWS SDK for Python" name = "boto3" optional = false python-versions = "*" -version = "1.12.32" +version = "1.15.5" [package.dependencies] -botocore = ">=1.15.32,<1.16.0" +botocore = ">=1.18.5,<1.19.0" jmespath = ">=0.7.1,<1.0.0" s3transfer = ">=0.3.0,<0.4.0" @@ -96,10 +97,9 @@ description = "Low-level, data-driven core of boto 3." name = "botocore" optional = false python-versions = "*" -version = "1.15.32" +version = "1.18.5" [package.dependencies] -docutils = ">=0.10,<0.16" jmespath = ">=0.7.1,<1.0.0" python-dateutil = ">=2.1,<3.0.0" @@ -146,7 +146,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.2.1" +version = "5.3" [package.dependencies] [package.dependencies.toml] @@ -158,11 +158,12 @@ toml = ["toml"] [[package]] category = "main" -description = "Docutils -- Python Documentation Utilities" -name = "docutils" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "0.15.2" +description = "A backport of the dataclasses module for Python 3.6" +marker = "python_version < \"3.7\"" +name = "dataclasses" +optional = true +python-versions = "*" +version = "0.6" [[package]] category = "dev" @@ -352,7 +353,7 @@ description = "Python Git Library" name = "gitpython" optional = false python-versions = ">=3.4" -version = "3.1.7" +version = "3.1.8" [package.dependencies] gitdb = ">=4.0.1,<5" @@ -371,7 +372,7 @@ description = "Read metadata from Python packages" name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.7.0" +version = "2.0.0" [package.dependencies] zipp = ">=0.5" @@ -512,8 +513,8 @@ category = "dev" description = "Python Build Reasonableness" name = "pbr" optional = false -python-versions = "*" -version = "5.4.5" +python-versions = ">=2.6" +version = "5.5.0" [[package]] category = "dev" @@ -559,6 +560,24 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.6.0" +[[package]] +category = "main" +description = "Data validation and settings management using python 3.6 type hinting" +name = "pydantic" +optional = true +python-versions = ">=3.6" +version = "1.6.1" + +[package.dependencies] +[package.dependencies.dataclasses] +python = "<3.7" +version = ">=0.6" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] +typing_extensions = ["typing-extensions (>=3.7.2)"] + [[package]] category = "dev" description = "passive checker of Python programs" @@ -669,10 +688,9 @@ description = "Code Metrics in Python" name = "radon" optional = false python-versions = "*" -version = "4.2.0" +version = "4.3.2" [package.dependencies] -flake8-polyfill = "*" future = "*" mando = ">=0.6,<0.7" @@ -680,6 +698,9 @@ mando = ">=0.6,<0.7" python = ">=3.5" version = ">=0.4.1" +[package.extras] +flake8 = ["flake8-polyfill"] + [[package]] category = "dev" description = "Alternative regular expression module, to replace re." @@ -739,7 +760,7 @@ description = "Manage dynamic plugins for Python applications" name = "stevedore" optional = false python-versions = ">=3.6" -version = "3.2.0" +version = "3.2.2" [package.dependencies] pbr = ">=2.0.0,<2.1.0 || >2.1.0" @@ -754,7 +775,7 @@ description = "A collection of helpers and mock objects for unit tests and doc t name = "testfixtures" optional = false python-versions = "*" -version = "6.14.1" +version = "6.14.2" [package.extras] build = ["setuptools-git", "wheel", "twine"] @@ -777,6 +798,14 @@ optional = false python-versions = "*" version = "1.4.1" +[[package]] +category = "main" +description = "Backported and Experimental Type Hints for Python 3.5+" +name = "typing-extensions" +optional = true +python-versions = "*" +version = "3.7.4.3" + [[package]] category = "main" description = "HTTP library with thread-safe connection pooling, file post, and more." @@ -812,27 +841,34 @@ description = "Monitor code metrics for Python on your CI server" name = "xenon" optional = false python-versions = "*" -version = "0.7.0" +version = "0.7.1" [package.dependencies] PyYAML = ">=4.2b1,<6.0" -radon = ">=4,<5" requests = ">=2.0,<3.0" +[package.dependencies.radon] +extras = ["flake8"] +version = ">=4,<5" + [[package]] category = "main" description = "Backport of pathlib-compatible object wrapper for zip files" +marker = "python_version < \"3.8\"" name = "zipp" optional = false python-versions = ">=3.6" -version = "3.1.0" +version = "3.2.0" [package.extras] docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["jaraco.itertools", "func-timeout"] +testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] + +[extras] +pydantic = ["pydantic", "typing_extensions"] [metadata] -content-hash = "a2036c75a7509f15f2273d2d907fa4d1418f56e76a948994ae01ce0e26a0175a" +content-hash = "f2207b4e243108a8b2b2eee5a56f648519d2ce8cb893f4e3c8fb346a44374eaa" lock-version = "1.0" python-versions = "^3.6" @@ -846,8 +882,8 @@ atomicwrites = [ {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-20.1.0-py2.py3-none-any.whl", hash = "sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff"}, - {file = "attrs-20.1.0.tar.gz", hash = "sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a"}, + {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, + {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, ] aws-xray-sdk = [ {file = "aws-xray-sdk-2.6.0.tar.gz", hash = "sha256:abf5b90f740e1f402e23414c9670e59cb9772e235e271fef2bce62b9100cbc77"}, @@ -862,12 +898,12 @@ black = [ {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, ] boto3 = [ - {file = "boto3-1.12.32-py2.py3-none-any.whl", hash = "sha256:57398de1b5e074e715c866441e69f90c9468959d5743a021d8aeed04fbaa1078"}, - {file = "boto3-1.12.32.tar.gz", hash = "sha256:60ac1124597231ed36a7320547cd0d16a001bb92333ab30ad20514f77e585225"}, + {file = "boto3-1.15.5-py2.py3-none-any.whl", hash = "sha256:0c464a7de522f88b581ca0d41ffa71e9be5e17fbb0456c275421f65b7c5f6a55"}, + {file = "boto3-1.15.5.tar.gz", hash = "sha256:0fce548e19d6db8e11fd0e2ae7809e1e3282080636b4062b2452bfa20e4f0233"}, ] botocore = [ - {file = "botocore-1.15.32-py2.py3-none-any.whl", hash = "sha256:a963af564d94107787ff3d2c534e8b7aed7f12e014cdd609f8fcb17bf9d9b19a"}, - {file = "botocore-1.15.32.tar.gz", hash = "sha256:3ea89601ee452b65084005278bd832be854cfde5166685dcb14b6c8f19d3fc6d"}, + {file = "botocore-1.18.5-py2.py3-none-any.whl", hash = "sha256:e3bf44fba058f6df16006b94a67650418a080a525c82521abb3cb516a4cba362"}, + {file = "botocore-1.18.5.tar.gz", hash = "sha256:7ce7a05b98ffb3170396960273383e8aade9be6026d5a762f5f40969d5d6b761"}, ] certifi = [ {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, @@ -886,45 +922,44 @@ colorama = [ {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, ] coverage = [ - {file = "coverage-5.2.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:40f70f81be4d34f8d491e55936904db5c527b0711b2a46513641a5729783c2e4"}, - {file = "coverage-5.2.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:675192fca634f0df69af3493a48224f211f8db4e84452b08d5fcebb9167adb01"}, - {file = "coverage-5.2.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2fcc8b58953d74d199a1a4d633df8146f0ac36c4e720b4a1997e9b6327af43a8"}, - {file = "coverage-5.2.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:64c4f340338c68c463f1b56e3f2f0423f7b17ba6c3febae80b81f0e093077f59"}, - {file = "coverage-5.2.1-cp27-cp27m-win32.whl", hash = "sha256:52f185ffd3291196dc1aae506b42e178a592b0b60a8610b108e6ad892cfc1bb3"}, - {file = "coverage-5.2.1-cp27-cp27m-win_amd64.whl", hash = "sha256:30bc103587e0d3df9e52cd9da1dd915265a22fad0b72afe54daf840c984b564f"}, - {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9ea749fd447ce7fb1ac71f7616371f04054d969d412d37611716721931e36efd"}, - {file = "coverage-5.2.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ce7866f29d3025b5b34c2e944e66ebef0d92e4a4f2463f7266daa03a1332a651"}, - {file = "coverage-5.2.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:4869ab1c1ed33953bb2433ce7b894a28d724b7aa76c19b11e2878034a4e4680b"}, - {file = "coverage-5.2.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a3ee9c793ffefe2944d3a2bd928a0e436cd0ac2d9e3723152d6fd5398838ce7d"}, - {file = "coverage-5.2.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28f42dc5172ebdc32622a2c3f7ead1b836cdbf253569ae5673f499e35db0bac3"}, - {file = "coverage-5.2.1-cp35-cp35m-win32.whl", hash = "sha256:e26c993bd4b220429d4ec8c1468eca445a4064a61c74ca08da7429af9bc53bb0"}, - {file = "coverage-5.2.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4186fc95c9febeab5681bc3248553d5ec8c2999b8424d4fc3a39c9cba5796962"}, - {file = "coverage-5.2.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:b360d8fd88d2bad01cb953d81fd2edd4be539df7bfec41e8753fe9f4456a5082"}, - {file = "coverage-5.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1adb6be0dcef0cf9434619d3b892772fdb48e793300f9d762e480e043bd8e716"}, - {file = "coverage-5.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:098a703d913be6fbd146a8c50cc76513d726b022d170e5e98dc56d958fd592fb"}, - {file = "coverage-5.2.1-cp36-cp36m-win32.whl", hash = "sha256:962c44070c281d86398aeb8f64e1bf37816a4dfc6f4c0f114756b14fc575621d"}, - {file = "coverage-5.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1ed2bdb27b4c9fc87058a1cb751c4df8752002143ed393899edb82b131e0546"}, - {file = "coverage-5.2.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:c890728a93fffd0407d7d37c1e6083ff3f9f211c83b4316fae3778417eab9811"}, - {file = "coverage-5.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:538f2fd5eb64366f37c97fdb3077d665fa946d2b6d95447622292f38407f9258"}, - {file = "coverage-5.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:27ca5a2bc04d68f0776f2cdcb8bbd508bbe430a7bf9c02315cd05fb1d86d0034"}, - {file = "coverage-5.2.1-cp37-cp37m-win32.whl", hash = "sha256:aab75d99f3f2874733946a7648ce87a50019eb90baef931698f96b76b6769a46"}, - {file = "coverage-5.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:c2ff24df02a125b7b346c4c9078c8936da06964cc2d276292c357d64378158f8"}, - {file = "coverage-5.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:304fbe451698373dc6653772c72c5d5e883a4aadaf20343592a7abb2e643dae0"}, - {file = "coverage-5.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c96472b8ca5dc135fb0aa62f79b033f02aa434fb03a8b190600a5ae4102df1fd"}, - {file = "coverage-5.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8505e614c983834239f865da2dd336dcf9d72776b951d5dfa5ac36b987726e1b"}, - {file = "coverage-5.2.1-cp38-cp38-win32.whl", hash = "sha256:700997b77cfab016533b3e7dbc03b71d33ee4df1d79f2463a318ca0263fc29dd"}, - {file = "coverage-5.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:46794c815e56f1431c66d81943fa90721bb858375fb36e5903697d5eef88627d"}, - {file = "coverage-5.2.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:16042dc7f8e632e0dcd5206a5095ebd18cb1d005f4c89694f7f8aafd96dd43a3"}, - {file = "coverage-5.2.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c1bbb628ed5192124889b51204de27c575b3ffc05a5a91307e7640eff1d48da4"}, - {file = "coverage-5.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4f6428b55d2916a69f8d6453e48a505c07b2245653b0aa9f0dee38785939f5e4"}, - {file = "coverage-5.2.1-cp39-cp39-win32.whl", hash = "sha256:9e536783a5acee79a9b308be97d3952b662748c4037b6a24cbb339dc7ed8eb89"}, - {file = "coverage-5.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b"}, - {file = "coverage-5.2.1.tar.gz", hash = "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b"}, -] -docutils = [ - {file = "docutils-0.15.2-py2-none-any.whl", hash = "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827"}, - {file = "docutils-0.15.2-py3-none-any.whl", hash = "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0"}, - {file = "docutils-0.15.2.tar.gz", hash = "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"}, + {file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"}, + {file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"}, + {file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"}, + {file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"}, + {file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"}, + {file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"}, + {file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"}, + {file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"}, + {file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"}, + {file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"}, + {file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"}, + {file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"}, + {file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"}, + {file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"}, + {file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"}, + {file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"}, + {file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"}, + {file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"}, + {file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"}, + {file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"}, + {file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"}, + {file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"}, + {file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"}, + {file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"}, + {file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"}, + {file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"}, + {file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"}, + {file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"}, + {file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"}, + {file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"}, + {file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"}, + {file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"}, + {file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"}, + {file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"}, +] +dataclasses = [ + {file = "dataclasses-0.6-py3-none-any.whl", hash = "sha256:454a69d788c7fda44efd71e259be79577822f5e3f53f029a22d08004e951dc9f"}, + {file = "dataclasses-0.6.tar.gz", hash = "sha256:6988bd2b895eef432d562370bb707d540f32f7360ab13da45340101bc2307d84"}, ] eradicate = [ {file = "eradicate-1.0.tar.gz", hash = "sha256:4ffda82aae6fd49dfffa777a857cb758d77502a1f2e0f54c9ac5155a39d2d01a"}, @@ -982,16 +1017,16 @@ gitdb = [ {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, ] gitpython = [ - {file = "GitPython-3.1.7-py3-none-any.whl", hash = "sha256:fa3b92da728a457dd75d62bb5f3eb2816d99a7fe6c67398e260637a40e3fafb5"}, - {file = "GitPython-3.1.7.tar.gz", hash = "sha256:2db287d71a284e22e5c2846042d0602465c7434d910406990d5b74df4afb0858"}, + {file = "GitPython-3.1.8-py3-none-any.whl", hash = "sha256:1858f4fd089abe92ae465f01d5aaaf55e937eca565fb2c1fce35a51b5f85c910"}, + {file = "GitPython-3.1.8.tar.gz", hash = "sha256:080bf8e2cf1a2b907634761c2eaefbe83b69930c94c66ad11b65a8252959f912"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, - {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, + {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"}, + {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"}, ] isort = [ {file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"}, @@ -1069,8 +1104,8 @@ pathspec = [ {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, ] pbr = [ - {file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"}, - {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"}, + {file = "pbr-5.5.0-py2.py3-none-any.whl", hash = "sha256:5adc0f9fc64319d8df5ca1e4e06eea674c26b80e6f00c530b18ce6a6592ead15"}, + {file = "pbr-5.5.0.tar.gz", hash = "sha256:14bfd98f51c78a3dd22a1ef45cf194ad79eee4a19e8e1a0d5c7f8e81ffe182ea"}, ] pdoc3 = [ {file = "pdoc3-0.7.5.tar.gz", hash = "sha256:ebca75b7fcf23f3b4320abe23339834d3f08c28517718e9d29e555fc38eeb33c"}, @@ -1087,6 +1122,25 @@ pycodestyle = [ {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, ] +pydantic = [ + {file = "pydantic-1.6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:418b84654b60e44c0cdd5384294b0e4bc1ebf42d6e873819424f3b78b8690614"}, + {file = "pydantic-1.6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4900b8820b687c9a3ed753684337979574df20e6ebe4227381d04b3c3c628f99"}, + {file = "pydantic-1.6.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b49c86aecde15cde33835d5d6360e55f5e0067bb7143a8303bf03b872935c75b"}, + {file = "pydantic-1.6.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2de562a456c4ecdc80cf1a8c3e70c666625f7d02d89a6174ecf63754c734592e"}, + {file = "pydantic-1.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f769141ab0abfadf3305d4fcf36660e5cf568a666dd3efab7c3d4782f70946b1"}, + {file = "pydantic-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2dc946b07cf24bee4737ced0ae77e2ea6bc97489ba5a035b603bd1b40ad81f7e"}, + {file = "pydantic-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:36dbf6f1be212ab37b5fda07667461a9219c956181aa5570a00edfb0acdfe4a1"}, + {file = "pydantic-1.6.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:1783c1d927f9e1366e0e0609ae324039b2479a1a282a98ed6a6836c9ed02002c"}, + {file = "pydantic-1.6.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:cf3933c98cb5e808b62fae509f74f209730b180b1e3c3954ee3f7949e083a7df"}, + {file = "pydantic-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f8af9b840a9074e08c0e6dc93101de84ba95df89b267bf7151d74c553d66833b"}, + {file = "pydantic-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:40d765fa2d31d5be8e29c1794657ad46f5ee583a565c83cea56630d3ae5878b9"}, + {file = "pydantic-1.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3fa799f3cfff3e5f536cbd389368fc96a44bb30308f258c94ee76b73bd60531d"}, + {file = "pydantic-1.6.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:6c3f162ba175678218629f446a947e3356415b6b09122dcb364e58c442c645a7"}, + {file = "pydantic-1.6.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:eb75dc1809875d5738df14b6566ccf9fd9c0bcde4f36b72870f318f16b9f5c20"}, + {file = "pydantic-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:530d7222a2786a97bc59ee0e0ebbe23728f82974b1f1ad9a11cd966143410633"}, + {file = "pydantic-1.6.1-py36.py37.py38-none-any.whl", hash = "sha256:b5b3489cb303d0f41ad4a7390cf606a5f2c7a94dcba20c051cd1c653694cb14d"}, + {file = "pydantic-1.6.1.tar.gz", hash = "sha256:54122a8ed6b75fe1dd80797f8251ad2063ea348a03b77218d73ea9fe19bd4e73"}, +] pyflakes = [ {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, @@ -1128,8 +1182,8 @@ pyyaml = [ {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, ] radon = [ - {file = "radon-4.2.0-py2.py3-none-any.whl", hash = "sha256:215e42c8748b5ca8ddf7c061831600b9e73e9c48770a81eeaaeeb066697aee15"}, - {file = "radon-4.2.0.tar.gz", hash = "sha256:b73f6f469c15c9616e0f7ce12080a9ecdee9f2335bdbb5ccea1f2bae26e8d20d"}, + {file = "radon-4.3.2-py2.py3-none-any.whl", hash = "sha256:b991de491eb2edbc2aac8f5f7ebf02b799852f076fa5a73fedf79d144d85e37e"}, + {file = "radon-4.3.2.tar.gz", hash = "sha256:758b3ab345aa86e95f642713612a57da7c7da6d552c4dbfbe397a67601ace7dd"}, ] regex = [ {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"}, @@ -1171,12 +1225,12 @@ smmap = [ {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, ] stevedore = [ - {file = "stevedore-3.2.0-py3-none-any.whl", hash = "sha256:c8f4f0ebbc394e52ddf49de8bcc3cf8ad2b4425ebac494106bbc5e3661ac7633"}, - {file = "stevedore-3.2.0.tar.gz", hash = "sha256:38791aa5bed922b0a844513c5f9ed37774b68edc609e5ab8ab8d8fe0ce4315e5"}, + {file = "stevedore-3.2.2-py3-none-any.whl", hash = "sha256:5e1ab03eaae06ef6ce23859402de785f08d97780ed774948ef16c4652c41bc62"}, + {file = "stevedore-3.2.2.tar.gz", hash = "sha256:f845868b3a3a77a2489d226568abe7328b5c2d4f6a011cc759dfa99144a521f0"}, ] testfixtures = [ - {file = "testfixtures-6.14.1-py2.py3-none-any.whl", hash = "sha256:30566e24a1b34e4d3f8c13abf62557d01eeb4480bcb8f1745467bfb0d415a7d9"}, - {file = "testfixtures-6.14.1.tar.gz", hash = "sha256:58d2b3146d93bc5ddb0cd24e0ccacb13e29bdb61e5c81235c58f7b8ee4470366"}, + {file = "testfixtures-6.14.2-py2.py3-none-any.whl", hash = "sha256:816557888877f498081c1b5c572049b4a2ddffedb77401308ff4cdc1bb9147b7"}, + {file = "testfixtures-6.14.2.tar.gz", hash = "sha256:14d9907390f5f9c7189b3d511b64f34f1072d07cc13b604a57e1bb79029376e3"}, ] toml = [ {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, @@ -1205,6 +1259,11 @@ typed-ast = [ {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, ] +typing-extensions = [ + {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, + {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, + {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, +] urllib3 = [ {file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"}, {file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"}, @@ -1217,10 +1276,10 @@ wrapt = [ {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] xenon = [ - {file = "xenon-0.7.0-py2.py3-none-any.whl", hash = "sha256:83e98f67b7077c95c25c3402aea6203dd2ed6256708b76ed9751e9dbf1aba125"}, - {file = "xenon-0.7.0.tar.gz", hash = "sha256:5e6433c9297d965bf666256a0a030b6e13660ab87680220c4eb07241f101625b"}, + {file = "xenon-0.7.1-py2.py3-none-any.whl", hash = "sha256:33d807ef805a2ed854adfcc7cc998398d5c0626a5ad443e52684b998a4dd4aa3"}, + {file = "xenon-0.7.1.tar.gz", hash = "sha256:38bf283135f0636355ecf6054b6f37226af12faab152161bda1a4f9e4dc5b701"}, ] zipp = [ - {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"}, - {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"}, + {file = "zipp-3.2.0-py3-none-any.whl", hash = "sha256:43f4fa8d8bb313e65d8323a3952ef8756bf40f9a5c3ea7334be23ee4ec8278b6"}, + {file = "zipp-3.2.0.tar.gz", hash = "sha256:b52f22895f4cfce194bc8172f3819ee8de7540aa6d873535a8668b730b8b411f"}, ] diff --git a/pyproject.toml b/pyproject.toml index d6c3f6e6022..61bc92ab26a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,8 @@ aws-xray-sdk = "^2.5.0" fastjsonschema = "^2.14.5" boto3 = "^1.12" jmespath = "^0.10.0" +pydantic = {version = "^1.6.0", optional = true } +typing_extensions = {version = "^3.7.4.2", optional = true } [tool.poetry.dev-dependencies] coverage = {extras = ["toml"], version = "^5.0.3"} @@ -36,6 +38,7 @@ flake8-debugger = "^3.2.1" flake8-fixme = "^1.1.1" flake8-isort = "^2.8.0" flake8-variables-names = "^0.0.3" +flake8_polyfill = "^1.0.2" isort = "^4.3.21" pytest-cov = "^2.8.1" pytest-mock = "^2.0.0" @@ -46,11 +49,10 @@ radon = "^4.1.0" xenon = "^0.7.0" flake8-eradicate = "^0.3.0" flake8-bugbear = "^20.1.4" -pydantic = {version = "^1.6.0", optional = true } [tool.poetry.extras] -advanced_parser = ["pydantic"] +pydantic = ["pydantic", "typing_extensions"] [tool.coverage.run] source = ["aws_lambda_powertools"] diff --git a/tests/functional/parser/schemas.py b/tests/functional/parser/schemas.py index 3667601e630..bafb31673d1 100644 --- a/tests/functional/parser/schemas.py +++ b/tests/functional/parser/schemas.py @@ -1,7 +1,6 @@ from typing import Dict, List, Optional from pydantic import BaseModel -from typing_extensions import Literal from aws_lambda_powertools.utilities.advanced_parser.schemas import ( DynamoDBSchema, @@ -11,6 +10,7 @@ SqsRecordSchema, SqsSchema, ) +from typing_extensions import Literal class MyDynamoBusiness(BaseModel): From a47056f6fb596e768b386829f99d9738536697e8 Mon Sep 17 00:00:00 2001 From: Ran Isenberg Date: Fri, 25 Sep 2020 20:44:12 +0300 Subject: [PATCH 14/14] fix: reduce complexity of dynamo envelope --- .../utilities/advanced_parser/envelopes/base.py | 4 ++++ .../utilities/advanced_parser/envelopes/dynamodb.py | 13 ++++++------- .../utilities/advanced_parser/schemas/dynamodb.py | 1 - .../utilities/advanced_parser/schemas/sqs.py | 1 - tests/functional/parser/schemas.py | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/aws_lambda_powertools/utilities/advanced_parser/envelopes/base.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/base.py index 5e00e2c09ac..7b0b9bceb32 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/envelopes/base.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/base.py @@ -9,6 +9,8 @@ class BaseEnvelope(ABC): def _parse_user_dict_schema(self, user_event: Dict[str, Any], schema: BaseModel) -> Any: + if user_event is None: + return None logger.debug("parsing user dictionary schema") try: return schema(**user_event) @@ -17,6 +19,8 @@ def _parse_user_dict_schema(self, user_event: Dict[str, Any], schema: BaseModel) raise def _parse_user_json_string_schema(self, user_event: str, schema: BaseModel) -> Any: + if user_event is None: + return None logger.debug("parsing user dictionary schema") if schema == str: logger.debug("input is string, returning") diff --git a/aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py b/aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py index 22dad9efb22..95c294c2f1e 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py +++ b/aws_lambda_powertools/utilities/advanced_parser/envelopes/dynamodb.py @@ -18,11 +18,10 @@ def parse(self, event: Dict[str, Any], schema: BaseModel) -> Any: raise output = [] for record in parsed_envelope.Records: - parsed_new_image = ( - None if not record.dynamodb.NewImage else self._parse_user_dict_schema(record.dynamodb.NewImage, schema) - ) # noqa: E501 - parsed_old_image = ( - None if not record.dynamodb.OldImage else self._parse_user_dict_schema(record.dynamodb.OldImage, schema) - ) # noqa: E501 - output.append({"NewImage": parsed_new_image, "OldImage": parsed_old_image}) + output.append( + { + "NewImage": self._parse_user_dict_schema(record.dynamodb.NewImage, schema), + "OldImage": self._parse_user_dict_schema(record.dynamodb.OldImage, schema), + } + ) return output diff --git a/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py index 94c24f3313c..484d25cc7b7 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py +++ b/aws_lambda_powertools/utilities/advanced_parser/schemas/dynamodb.py @@ -2,7 +2,6 @@ from typing import Any, Dict, List, Optional from pydantic import BaseModel, root_validator - from typing_extensions import Literal diff --git a/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py b/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py index 416d26a6d54..d4b3c09ddd6 100644 --- a/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py +++ b/aws_lambda_powertools/utilities/advanced_parser/schemas/sqs.py @@ -3,7 +3,6 @@ from typing import Dict, List, Optional from pydantic import BaseModel, root_validator, validator - from typing_extensions import Literal diff --git a/tests/functional/parser/schemas.py b/tests/functional/parser/schemas.py index bafb31673d1..3667601e630 100644 --- a/tests/functional/parser/schemas.py +++ b/tests/functional/parser/schemas.py @@ -1,6 +1,7 @@ from typing import Dict, List, Optional from pydantic import BaseModel +from typing_extensions import Literal from aws_lambda_powertools.utilities.advanced_parser.schemas import ( DynamoDBSchema, @@ -10,7 +11,6 @@ SqsRecordSchema, SqsSchema, ) -from typing_extensions import Literal class MyDynamoBusiness(BaseModel):