diff --git a/python/.flake8 b/.flake8
similarity index 100%
rename from python/.flake8
rename to .flake8
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index 54d1e4b1a86..604219724f7 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -1,25 +1,18 @@
-name: Powertools Python
+name: Build
on:
pull_request:
branches:
- develop
- master
- paths:
- - "python/**"
push:
branches:
- develop
- master
- paths:
- - "python/**"
jobs:
build:
runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: ./python/
strategy:
max-parallel: 4
matrix:
diff --git a/.github/workflows/python_docs.yml b/.github/workflows/python_docs.yml
index b57bd29a475..57ef3eb4013 100644
--- a/.github/workflows/python_docs.yml
+++ b/.github/workflows/python_docs.yml
@@ -1,23 +1,16 @@
-name: Powertools Python Docs
+name: Docs
on:
pull_request:
branches:
- master
- paths:
- - "python/**"
push:
branches:
- master
- paths:
- - "python/**"
jobs:
docs:
runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: ./python/
steps:
- uses: actions/checkout@v1
- name: Set up Python
@@ -32,4 +25,4 @@ jobs:
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- publish_dir: python/docs/aws_lambda_powertools/
+ publish_dir: docs/aws_lambda_powertools/
diff --git a/.gitignore b/.gitignore
index 68c23bc3257..d12573e83a0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -291,5 +291,7 @@ $RECYCLE.BIN/
# End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode
# Misc
-test_report
-/.idea/*
+test_report
+wheelhouse
+docs
+/.idea/*
diff --git a/python/MANIFEST.in b/MANIFEST.in
similarity index 100%
rename from python/MANIFEST.in
rename to MANIFEST.in
diff --git a/python/Makefile b/Makefile
similarity index 100%
rename from python/Makefile
rename to Makefile
diff --git a/README.md b/README.md
index 9f53b6e1178..49e6b3fffd4 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,447 @@
# Lambda Powertools
-
+
+  
A suite of utilities for AWS Lambda Functions that makes tracing with AWS X-Ray, structured logging and creating custom metrics asynchronously easier.
+* **Status**: Release candidate
+* **How long until GA?**: [Current progress](https://github.com/awslabs/aws-lambda-powertools/projects/1)
+
+## Features
+
+* **[Tracing](###Tracing)** - Decorators and utilities to trace Lambda function handlers, and both synchronous and asynchronous functions
+* **[Logging](###Logging)** - Structured logging made easier, and decorator to enrich structured logging with key Lambda context details
+* **[Metrics](###Metrics)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF)
+* **[Bring your own middleware](###Bring-your-own-middleware)** - Decorator factory to create your own middleware to run logic before, and after each Lambda invocation
+
+## Usage
+
+See **[example](./example/README.md)** of all features, testing, and a SAM template with all Powertools env vars. All features also provide full docs, and code completion for VSCode and PyCharm.
+
+### Installation
+
+With [pip](https://pip.pypa.io/en/latest/index.html) installed, run: ``pip install aws-lambda-powertools``
+
+### Environment variables
+
+**Environment variables** used across suite of utilities
+
+Environment variable | Description | Default | Utility
+------------------------------------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------
+POWERTOOLS_SERVICE_NAME | Sets service name used for tracing namespace, metrics dimensions and structured logging | "service_undefined" | all
+POWERTOOLS_TRACE_DISABLED | Disables tracing | "false" | [Tracing](###Tracing)
+POWERTOOLS_TRACE_MIDDLEWARES | Creates sub-segment for each middleware created by lambda_handler_decorator | "false" | [middleware_factory](###Bring-your-own-middleware)
+POWERTOOLS_LOGGER_LOG_EVENT | Logs incoming event | "false" | [Logging](###Logging)
+POWERTOOLS_LOGGER_SAMPLE_RATE | Debug log sampling | 0 | [Logging](###Logging)
+POWERTOOLS_METRICS_NAMESPACE | Metrics namespace | None | [Metrics](###Metrics)
+LOG_LEVEL | Sets logging level | "INFO" | [Logging](###Logging)
+
+### Tracing
+
+**Key features**
+
+* Capture cold start as annotation, and response and exceptions as metadata
+* Run functions locally with SAM CLI without code change to disable tracing
+* Explicitly disable tracing via env var `POWERTOOLS_TRACE_DISABLED="true"`
+* Support tracing async methods
+
+#### Tracing Lambda handler and a function
+
+```python
+from aws_lambda_powertools.tracing import Tracer
+tracer = Tracer()
+# tracer = Tracer(service="payment") # can also be explicitly defined
+
+@tracer.capture_method
+def collect_payment(charge_id):
+ ret = requests.post(PAYMENT_ENDPOINT) # logic
+ tracer.put_annotation("PAYMENT_STATUS", "SUCCESS") # custom annotation
+ return ret
+
+@tracer.capture_lambda_handler
+def handler(event, context)
+ charge_id = event.get('charge_id')
+ payment = collect_payment(charge_id)
+ ...
+```
+
+#### Tracing asynchronous functions
+
+```python
+import asyncio
+
+from aws_lambda_powertools.tracing import Tracer
+tracer = Tracer()
+# tracer = Tracer(service="payment") # can also be explicitly defined
+
+@tracer.capture_method
+async def collect_payment(charge_id):
+ ...
+
+@tracer.capture_lambda_handler
+def handler(event, context)
+ charge_id = event.get('charge_id')
+ payment = asyncio.run(collect_payment(charge_id)) # python 3.7+
+ ...
+```
+
+#### Tracing concurrent asynchronous with gather
+
+:warning: This will no longer be necessary after [this X-Ray recorder issue is resolved](https://github.com/aws/aws-xray-sdk-python/issues/164) as it's an edge case. :warning:
+
+To safely workaround this issue, use `@tracer.capture_method` on functions not being run with `async.gather`, and instead use `in_subsegment_async` context manager escape hatch to have the same tracing effect.
+
+
+```python
+import asyncio
+
+from aws_lambda_powertools.tracing import Tracer
+tracer = Tracer()
+# tracer = Tracer(service="payment") # can also be explicitly defined
+
+async def another_async_task():
+ async with tracer.provider.in_subsegment_async("## another_async_task"):
+ ...
+
+async def another_async_task_2():
+ async with tracer.provider.in_subsegment_async("## another_async_task_2"):
+ ...
+
+@tracer.capture_method
+async def collect_payment(charge_id):
+ asyncio.gather(another_async_task(), another_async_task_2())
+ ...
+
+@tracer.capture_lambda_handler
+def handler(event, context)
+ charge_id = event.get('charge_id')
+ payment = asyncio.run(collect_payment(charge_id)) # python 3.7+
+ ...
+```
+
+#### Using escape hatch mechanisms
+
+You can use `tracer.provider` attribute to access all methods provided by `xray_recorder`. This is useful when you need a feature available in X-Ray that is not available in the Tracer middleware, for example [thread-safe](https://github.com/aws/aws-xray-sdk-python/#user-content-trace-threadpoolexecutor), or [context managers](https://github.com/aws/aws-xray-sdk-python/#user-content-start-a-custom-segmentsubsegment).
+
+**Example using aiohttp with an async context manager**
+
+> NOTE: It expects you have `aiohttp` as a dependency. `aiohttp_trace_config` uses lazy import to create a trace_config object following `aiohttp` protocol.
+
+```python
+import asyncio
+import aiohttp
+
+from aws_lambda_powertools.tracing import Tracer, aiohttp_trace_config
+tracer = Tracer()
+
+# aiohttp_trace_config is x-ray extension for aiohttp trace config known as aws_xray_trace_config
+
+async def aiohttp_task():
+ # Async context manager as opposed to `@tracer.capture_method`
+ 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 aiohttp_task()
+ ...
+
+ return {
+ "task": "done",
+ **ret
+ }
+
+@tracer.capture_lambda_handler
+def handler(event, context)
+ ret = asyncio.run(async_tasks()) # python 3.7+
+ ...
+```
+
+#### Using a pre-configured tracer anywhere
+
+```python
+# handler.py
+from aws_lambda_powertools.tracing import Tracer
+tracer = Tracer(service="payment")
+
+@tracer.capture_lambda_handler
+def handler(event, context)
+ charge_id = event.get('charge_id')
+ payment = collect_payment(charge_id)
+ ...
+
+# another_file.py
+from aws_lambda_powertools.tracing import Tracer
+tracer = Tracer(auto_patch=False) # new instance using existing configuration with auto patching overriden
+```
+
+### Logging
+
+**Key features**
+
+* Capture key fields from Lambda context, cold start and structures logging output as JSON
+* Log Lambda event when instructed (disabled by default)
+ - Enable via `POWERTOOLS_LOGGER_LOG_EVENT="true"` or explicitly via decorator param
+* Log sampling enables DEBUG log level for a percentage of requests (disabled by default)
+ - Enable via `POWERTOOLS_LOGGER_SAMPLE_RATE=0.1`, ranges from 0 to 1, where 0.1 is 10% and 1 is 100%
+* Append additional keys to structured log at any point in time
+
+#### Structuring logs with Lambda context info
+
+```python
+from aws_lambda_powertools.logging import Logger
+
+logger = Logger()
+# Logger(service="payment", level="INFO") # also accepts explicit service name, log level
+
+@logger.inject_lambda_context
+def handler(event, context)
+ logger.info("Collecting payment")
+ ...
+ # You can log entire objects too
+ logger.info({
+ "operation": "collect_payment",
+ "charge_id": event['charge_id']
+ })
+ ...
+```
+
+
+Exerpt output in CloudWatch Logs
+
+```json
+{
+ "timestamp":"2019-08-22 18:17:33,774",
+ "level":"INFO",
+ "location":"collect.handler:1",
+ "service":"payment",
+ "lambda_function_name":"test",
+ "lambda_function_memory_size":"128",
+ "lambda_function_arn":"arn:aws:lambda:eu-west-1:12345678910:function:test",
+ "lambda_request_id":"52fdfc07-2182-154f-163f-5f0f9a621d72",
+ "cold_start": "true",
+ "sampling_rate": 0.1,
+ "message": "Collecting payment"
+}
+
+{
+ "timestamp":"2019-08-22 18:17:33,774",
+ "level":"INFO",
+ "location":"collect.handler:15",
+ "service":"payment",
+ "lambda_function_name":"test",
+ "lambda_function_memory_size":"128",
+ "lambda_function_arn":"arn:aws:lambda:eu-west-1:12345678910:function:test",
+ "lambda_request_id":"52fdfc07-2182-154f-163f-5f0f9a621d72",
+ "cold_start": "true",
+ "sampling_rate": 0.1,
+ "message":{
+ "operation":"collect_payment",
+ "charge_id": "ch_AZFlk2345C0"
+ }
+}
+```
+
+
+#### Appending additional keys to current logger
+
+```python
+from aws_lambda_powertools.logging import Logger
+
+logger = Logger()
+
+@logger.inject_lambda_context
+def handler(event, context)
+ if "order_id" in event:
+ logger.structure_logs(append=True, order_id=event["order_id"])
+ logger.info("Collecting payment")
+ ...
+```
+
+
+Exerpt output in CloudWatch Logs
+
+```json
+{
+ "timestamp":"2019-08-22 18:17:33,774",
+ "level":"INFO",
+ "location":"collect.handler:1",
+ "service":"payment",
+ "lambda_function_name":"test",
+ "lambda_function_memory_size":"128",
+ "lambda_function_arn":"arn:aws:lambda:eu-west-1:12345678910:function:test",
+ "lambda_request_id":"52fdfc07-2182-154f-163f-5f0f9a621d72",
+ "cold_start": "true",
+ "sampling_rate": 0.1,
+ "order_id": "order_id_value",
+ "message": "Collecting payment"
+}
+```
+
+
+### Metrics
+
+**Key features**
+
+* Aggregate up to 100 metrics using a single CloudWatch Embedded Metric Format (EMF) object (large JSON blob)
+* Context manager to create an one off metric with a different dimension than metrics already aggregated
+* Validate against common metric definitions mistakes (metric unit, values, max dimensions, max metrics, etc)
+* Metrics are created asynchronously by CloudWatch service, no custom stacks needed
+* EMF Metrics validation before publishing
+ - At least of one Metric and Dimension
+ - Maximum of 9 dimensions
+ - Only one Namespace
+ - [Any Metric unit supported by CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html)
+
+#### Creating multiple metrics
+
+If using multiple middlewares, use `log_metrics` as the last decorator, or else it will fail with `SchemaValidationError` if no metrics are recorded.
+
+```python
+from aws_lambda_powertools.metrics import Metrics, MetricUnit
+
+metrics = Metrics()
+metrics.add_namespace(name="ServerlessAirline")
+metrics.add_metric(name="ColdStart", unit="Count", value=1)
+metrics.add_dimension(name="service", value="booking")
+
+@metrics.log_metrics
+@tracer.capture_lambda_handler
+def lambda_handler(evt, ctx):
+ metrics.add_metric(name="BookingConfirmation", unit="Count", value=1)
+ some_code()
+ return True
+
+def some_code():
+ metrics.add_metric(name="some_other_metric", unit=MetricUnit.Seconds, value=1)
+ ...
+```
+
+CloudWatch EMF uses the same dimensions across all metrics. If you have metrics that should have different dimensions, use `single_metric` to create a single metric with any dimension you want. Generally, this would be an edge case since you [pay for unique metric](https://aws.amazon.com/cloudwatch/pricing/)
+
+> unique metric = (metric_name + dimension_name + dimension_value)
+
+```python
+from aws_lambda_powertools.metrics import MetricUnit, single_metric
+
+with single_metric(name="ColdStart", unit=MetricUnit.Count, value=1) as metric:
+ metric.add_dimension(name="function_context", value="$LATEST")
+```
+
+> **NOTE**: When using Metrics() in multiple places in your code, make sure to use `POWERTOOLS_METRICS_NAMESPACE` env var, or setting namespace param.
+
+### Bring your own middleware
+
+**Key features**
+
+* Utility to easily create your own middleware
+* Run logic before, after, and handle exceptions
+* Receive lambda handler, event, context
+* Optionally create sub-segment for each custom middleware
+
+This feature allows you to create your own middleware as a decorator with ease by following a simple signature.
+
+* Accept 3 mandatory args - `handler, event, context`
+* Always return the handler with event/context or response if executed
+ - Supports nested middleware/decorators use case
+
+#### Middleware with no params
+
+```python
+from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
+
+@lambda_handler_decorator
+def middleware_name(handler, event, context):
+ return handler(event, context)
+
+@lambda_handler_decorator
+def middleware_before_after(handler, event, context):
+ logic_before_handler_execution()
+ response = handler(event, context)
+ logic_after_handler_execution()
+ return response
+
+
+# middleware_name will wrap Lambda handler
+# and simply return the handler as we're not pre/post-processing anything
+# then middleware_before_after will wrap middleware_name
+# run some code before/after calling the handler returned by middleware_name
+# This way, lambda_handler is only actually called once (top-down)
+@middleware_before_after # This will run last
+@middleware_name # This will run first
+def lambda_handler(event, context):
+ return True
+```
+
+#### Middleware with params
+
+```python
+@lambda_handler_decorator
+def obfuscate_sensitive_data(handler, event, context, fields=None):
+ # Obfuscate email before calling Lambda handler
+ if fields:
+ for field in fields:
+ field = event.get(field, "")
+ event[field] = obfuscate_pii(field)
+
+ return handler(event, context)
+
+@obfuscate_sensitive_data(fields=["email"])
+def lambda_handler(event, context):
+ return True
+```
+
+#### Tracing middleware execution
+
+This makes use of an existing Tracer instance that you may have initialized anywhere in your code. If no Tracer instance is found, it'll initialize one using default options.
+
+```python
+from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
+
+@lambda_handler_decorator(trace_execution=True)
+def middleware_name(handler, event, context):
+ return handler(event, context)
+
+@middleware_name
+def lambda_handler(event, context):
+ return True
+```
+
+Optionally, you can enrich the final trace with additional annotations and metadata by retrieving a copy of the Tracer used.
+
+```python
+from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
+from aws_lambda_powertools.tracing import Tracer
+
+@lambda_handler_decorator(trace_execution=True)
+def middleware_name(handler, event, context):
+ tracer = Tracer() # Takes a copy of an existing tracer instance
+ tracer.add_anotation...
+ tracer.metadata...
+ return handler(event, context)
+
+@middleware_name
+def lambda_handler(event, context):
+ return True
+```
+
+### Debug mode
+
+By default, all log statements from AWS Lambda Powertools package are suppressed. If you'd like to enable them, use `set_package_logger` utility:
+
+```python
+import aws_lambda_powertools
+aws_lambda_powertools.logging.logger.set_package_logger()
+...
+```
+
## Tenets
-* **AWS Lambda only** – We optimise for AWS Lambda function environments only. Utilities might work with web frameworks and non-Lambda environments, though they are not officially supported.
+* **AWS Lambda only** – We optimise for AWS Lambda function environments and supported runtimes only. Utilities might work with web frameworks and non-Lambda environments, though they are not officially supported.
* **Eases the adoption of best practices** – The main priority of the utilities is to facilitate best practices adoption, as defined in the AWS Well-Architected Serverless Lens; all other functionality is optional.
* **Keep it lean** – Additional dependencies are carefully considered for security and ease of maintenance, and prevent negatively impacting startup time.
* **We strive for backwards compatibility** – New features and changes should keep backwards compatibility. If a breaking change cannot be avoided, the deprecation and migration process should be clearly defined.
@@ -15,9 +450,6 @@ A suite of utilities for AWS Lambda Functions that makes tracing with AWS X-Ray,
_`*` Core utilities are Tracer, Logger and Metrics. Optional utilities may vary across languages._
-## Powertools available
-
-* [Python](./python/README.md)
## Credits
diff --git a/python/aws_lambda_powertools/__init__.py b/aws_lambda_powertools/__init__.py
similarity index 100%
rename from python/aws_lambda_powertools/__init__.py
rename to aws_lambda_powertools/__init__.py
diff --git a/python/aws_lambda_powertools/helper/__init__.py b/aws_lambda_powertools/helper/__init__.py
similarity index 100%
rename from python/aws_lambda_powertools/helper/__init__.py
rename to aws_lambda_powertools/helper/__init__.py
diff --git a/python/aws_lambda_powertools/helper/models.py b/aws_lambda_powertools/helper/models.py
similarity index 100%
rename from python/aws_lambda_powertools/helper/models.py
rename to aws_lambda_powertools/helper/models.py
diff --git a/python/aws_lambda_powertools/logging/__init__.py b/aws_lambda_powertools/logging/__init__.py
similarity index 100%
rename from python/aws_lambda_powertools/logging/__init__.py
rename to aws_lambda_powertools/logging/__init__.py
diff --git a/python/aws_lambda_powertools/logging/exceptions.py b/aws_lambda_powertools/logging/exceptions.py
similarity index 100%
rename from python/aws_lambda_powertools/logging/exceptions.py
rename to aws_lambda_powertools/logging/exceptions.py
diff --git a/python/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py
similarity index 100%
rename from python/aws_lambda_powertools/logging/logger.py
rename to aws_lambda_powertools/logging/logger.py
diff --git a/python/aws_lambda_powertools/metrics/__init__.py b/aws_lambda_powertools/metrics/__init__.py
similarity index 100%
rename from python/aws_lambda_powertools/metrics/__init__.py
rename to aws_lambda_powertools/metrics/__init__.py
diff --git a/python/aws_lambda_powertools/metrics/base.py b/aws_lambda_powertools/metrics/base.py
similarity index 100%
rename from python/aws_lambda_powertools/metrics/base.py
rename to aws_lambda_powertools/metrics/base.py
diff --git a/python/aws_lambda_powertools/metrics/exceptions.py b/aws_lambda_powertools/metrics/exceptions.py
similarity index 100%
rename from python/aws_lambda_powertools/metrics/exceptions.py
rename to aws_lambda_powertools/metrics/exceptions.py
diff --git a/python/aws_lambda_powertools/metrics/metric.py b/aws_lambda_powertools/metrics/metric.py
similarity index 100%
rename from python/aws_lambda_powertools/metrics/metric.py
rename to aws_lambda_powertools/metrics/metric.py
diff --git a/python/aws_lambda_powertools/metrics/metrics.py b/aws_lambda_powertools/metrics/metrics.py
similarity index 100%
rename from python/aws_lambda_powertools/metrics/metrics.py
rename to aws_lambda_powertools/metrics/metrics.py
diff --git a/python/aws_lambda_powertools/metrics/schema.json b/aws_lambda_powertools/metrics/schema.json
similarity index 100%
rename from python/aws_lambda_powertools/metrics/schema.json
rename to aws_lambda_powertools/metrics/schema.json
diff --git a/python/aws_lambda_powertools/middleware_factory/__init__.py b/aws_lambda_powertools/middleware_factory/__init__.py
similarity index 100%
rename from python/aws_lambda_powertools/middleware_factory/__init__.py
rename to aws_lambda_powertools/middleware_factory/__init__.py
diff --git a/python/aws_lambda_powertools/middleware_factory/exceptions.py b/aws_lambda_powertools/middleware_factory/exceptions.py
similarity index 100%
rename from python/aws_lambda_powertools/middleware_factory/exceptions.py
rename to aws_lambda_powertools/middleware_factory/exceptions.py
diff --git a/python/aws_lambda_powertools/middleware_factory/factory.py b/aws_lambda_powertools/middleware_factory/factory.py
similarity index 100%
rename from python/aws_lambda_powertools/middleware_factory/factory.py
rename to aws_lambda_powertools/middleware_factory/factory.py
diff --git a/python/aws_lambda_powertools/tracing/__init__.py b/aws_lambda_powertools/tracing/__init__.py
similarity index 100%
rename from python/aws_lambda_powertools/tracing/__init__.py
rename to aws_lambda_powertools/tracing/__init__.py
diff --git a/python/aws_lambda_powertools/tracing/extensions.py b/aws_lambda_powertools/tracing/extensions.py
similarity index 100%
rename from python/aws_lambda_powertools/tracing/extensions.py
rename to aws_lambda_powertools/tracing/extensions.py
diff --git a/python/aws_lambda_powertools/tracing/tracer.py b/aws_lambda_powertools/tracing/tracer.py
similarity index 100%
rename from python/aws_lambda_powertools/tracing/tracer.py
rename to aws_lambda_powertools/tracing/tracer.py
diff --git a/python/bandit.baseline b/bandit.baseline
similarity index 100%
rename from python/bandit.baseline
rename to bandit.baseline
diff --git a/python/build_linux_wheels.sh b/build_linux_wheels.sh
similarity index 100%
rename from python/build_linux_wheels.sh
rename to build_linux_wheels.sh
diff --git a/python/example/.gitignore b/example/.gitignore
similarity index 100%
rename from python/example/.gitignore
rename to example/.gitignore
diff --git a/python/example/README.md b/example/README.md
similarity index 100%
rename from python/example/README.md
rename to example/README.md
diff --git a/python/example/events/event.json b/example/events/event.json
similarity index 100%
rename from python/example/events/event.json
rename to example/events/event.json
diff --git a/python/example/hello_world/__init__.py b/example/hello_world/__init__.py
similarity index 100%
rename from python/example/hello_world/__init__.py
rename to example/hello_world/__init__.py
diff --git a/python/example/hello_world/app.py b/example/hello_world/app.py
similarity index 100%
rename from python/example/hello_world/app.py
rename to example/hello_world/app.py
diff --git a/python/example/hello_world/requirements.txt b/example/hello_world/requirements.txt
similarity index 100%
rename from python/example/hello_world/requirements.txt
rename to example/hello_world/requirements.txt
diff --git a/python/example/pytest.ini b/example/pytest.ini
similarity index 100%
rename from python/example/pytest.ini
rename to example/pytest.ini
diff --git a/python/example/requirements-dev.txt b/example/requirements-dev.txt
similarity index 100%
rename from python/example/requirements-dev.txt
rename to example/requirements-dev.txt
diff --git a/python/example/samconfig.toml b/example/samconfig.toml
similarity index 100%
rename from python/example/samconfig.toml
rename to example/samconfig.toml
diff --git a/python/example/template.yaml b/example/template.yaml
similarity index 100%
rename from python/example/template.yaml
rename to example/template.yaml
diff --git a/python/example/tests/test_handler.py b/example/tests/test_handler.py
similarity index 100%
rename from python/example/tests/test_handler.py
rename to example/tests/test_handler.py
diff --git a/python/poetry.lock b/poetry.lock
similarity index 93%
rename from python/poetry.lock
rename to poetry.lock
index 07143b50fa7..b5ec9af256f 100644
--- a/python/poetry.lock
+++ b/poetry.lock
@@ -199,14 +199,6 @@ optional = false
python-versions = "*"
version = "2020.4.5.1"
-[[package]]
-category = "dev"
-description = "Validate configuration and produce human readable error messages."
-name = "cfgv"
-optional = false
-python-versions = ">=3.6"
-version = "3.0.0"
-
[[package]]
category = "dev"
description = "Universal encoding detector for Python 2 and 3"
@@ -247,14 +239,6 @@ version = "*"
[package.extras]
toml = ["toml"]
-[[package]]
-category = "dev"
-description = "Distribution utilities"
-name = "distlib"
-optional = false
-python-versions = "*"
-version = "0.3.0"
-
[[package]]
category = "main"
description = "Docutils -- Python Documentation Utilities"
@@ -282,14 +266,6 @@ version = "2.14.4"
[package.extras]
devel = ["colorama", "jsonschema", "json-spec", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"]
-[[package]]
-category = "dev"
-description = "A platform independent file lock."
-name = "filelock"
-optional = false
-python-versions = "*"
-version = "3.0.12"
-
[[package]]
category = "dev"
description = "the modular source code checker: pep8 pyflakes and co"
@@ -464,17 +440,6 @@ version = "3.1.2"
[package.dependencies]
gitdb = ">=4.0.1,<5"
-[[package]]
-category = "dev"
-description = "File identification library for Python"
-name = "identify"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
-version = "1.4.15"
-
-[package.extras]
-license = ["editdistance"]
-
[[package]]
category = "dev"
description = "Internationalized Domain Names in Applications (IDNA)"
@@ -510,27 +475,6 @@ zipp = ">=0.5"
docs = ["sphinx", "rst.linker"]
testing = ["packaging", "importlib-resources"]
-[[package]]
-category = "dev"
-description = "Read resources from Python packages"
-marker = "python_version < \"3.7\""
-name = "importlib-resources"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
-version = "1.5.0"
-
-[package.dependencies]
-[package.dependencies.importlib-metadata]
-python = "<3.8"
-version = "*"
-
-[package.dependencies.zipp]
-python = "<3.8"
-version = ">=0.4"
-
-[package.extras]
-docs = ["sphinx", "rst.linker", "jaraco.packaging"]
-
[[package]]
category = "dev"
description = "A Python utility / library to sort Python imports."
@@ -646,14 +590,6 @@ optional = false
python-versions = ">=3.5"
version = "4.7.5"
-[[package]]
-category = "dev"
-description = "Node.js virtual environment builder"
-name = "nodeenv"
-optional = false
-python-versions = "*"
-version = "1.3.5"
-
[[package]]
category = "dev"
description = "Core utilities for Python packages"
@@ -710,30 +646,6 @@ version = ">=0.12"
[package.extras]
dev = ["pre-commit", "tox"]
-[[package]]
-category = "dev"
-description = "A framework for managing and maintaining multi-language pre-commit hooks."
-name = "pre-commit"
-optional = false
-python-versions = ">=3.6"
-version = "2.1.1"
-
-[package.dependencies]
-cfgv = ">=2.0.0"
-identify = ">=1.0.0"
-nodeenv = ">=0.11.1"
-pyyaml = ">=5.1"
-toml = "*"
-virtualenv = ">=15.2"
-
-[package.dependencies.importlib-metadata]
-python = "<3.8"
-version = "*"
-
-[package.dependencies.importlib-resources]
-python = "<3.7"
-version = "*"
-
[[package]]
category = "dev"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
@@ -983,32 +895,6 @@ brotli = ["brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
-[[package]]
-category = "dev"
-description = "Virtual Python Environment builder"
-name = "virtualenv"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
-version = "20.0.20"
-
-[package.dependencies]
-appdirs = ">=1.4.3,<2"
-distlib = ">=0.3.0,<1"
-filelock = ">=3.0.0,<4"
-six = ">=1.9.0,<2"
-
-[package.dependencies.importlib-metadata]
-python = "<3.8"
-version = ">=0.12,<2"
-
-[package.dependencies.importlib-resources]
-python = "<3.7"
-version = ">=1.0,<2"
-
-[package.extras]
-docs = ["sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)", "proselint (>=0.10.2)"]
-testing = ["pytest (>=4)", "coverage (>=5)", "coverage-enable-subprocess (>=1)", "pytest-xdist (>=1.31.0)", "pytest-mock (>=2)", "pytest-env (>=0.6.2)", "pytest-randomly (>=1)", "pytest-timeout", "packaging (>=20.0)", "xonsh (>=0.9.16)"]
-
[[package]]
category = "dev"
description = "Measures number of Terminal column cells of wide-character codes"
@@ -1053,7 +939,6 @@ multidict = ">=4.0"
[[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"
@@ -1064,7 +949,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["jaraco.itertools", "func-timeout"]
[metadata]
-content-hash = "525f4150dc764e0fa82b790ada43514e328c26e0e3e90e26103b038ce0bd896e"
+content-hash = "11587b6860e090c953a7e70372c266723b32848accdde9e3546e7ed9d5208a9f"
python-versions = "^3.6"
[metadata.files]
@@ -1134,10 +1019,6 @@ certifi = [
{file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"},
{file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"},
]
-cfgv = [
- {file = "cfgv-3.0.0-py2.py3-none-any.whl", hash = "sha256:f22b426ed59cd2ab2b54ff96608d846c33dfb8766a67f0b4a6ce130ce244414f"},
- {file = "cfgv-3.0.0.tar.gz", hash = "sha256:04b093b14ddf9fd4d17c53ebfd55582d27b76ed30050193c14e560770c5360eb"},
-]
chardet = [
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
@@ -1183,9 +1064,6 @@ coverage = [
{file = "coverage-5.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e"},
{file = "coverage-5.1.tar.gz", hash = "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"},
]
-distlib = [
- {file = "distlib-0.3.0.zip", hash = "sha256:2e166e231a26b36d6dfe35a48c4464346620f8645ed0ace01ee31822b288de21"},
-]
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"},
@@ -1198,10 +1076,6 @@ fastjsonschema = [
{file = "fastjsonschema-2.14.4-py3-none-any.whl", hash = "sha256:02a39b518077cc73c1a537f27776527dc6c1e5012d530eb8ac0d1062efbabff7"},
{file = "fastjsonschema-2.14.4.tar.gz", hash = "sha256:7292cde54f1c30172f78557509ad4cb152f374087fc844bd113a83e2ac494dd6"},
]
-filelock = [
- {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
- {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
-]
flake8 = [
{file = "flake8-3.8.1-py2.py3-none-any.whl", hash = "sha256:6c1193b0c3f853ef763969238f6c81e9e63ace9d024518edc020d5f1d6d93195"},
{file = "flake8-3.8.1.tar.gz", hash = "sha256:ea6623797bf9a52f4c9577d780da0bb17d65f870213f7b5bcc9fca82540c31d5"},
@@ -1254,10 +1128,6 @@ gitpython = [
{file = "GitPython-3.1.2-py3-none-any.whl", hash = "sha256:da3b2cf819974789da34f95ac218ef99f515a928685db141327c09b73dd69c09"},
{file = "GitPython-3.1.2.tar.gz", hash = "sha256:864a47472548f3ba716ca202e034c1900f197c0fb3a08f641c20c3cafd15ed94"},
]
-identify = [
- {file = "identify-1.4.15-py2.py3-none-any.whl", hash = "sha256:88ed90632023e52a6495749c6732e61e08ec9f4f04e95484a5c37b9caf40283c"},
- {file = "identify-1.4.15.tar.gz", hash = "sha256:23c18d97bb50e05be1a54917ee45cc61d57cb96aedc06aabb2b02331edf0dbf0"},
-]
idna = [
{file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"},
{file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"},
@@ -1269,10 +1139,6 @@ importlib-metadata = [
{file = "importlib_metadata-1.6.0-py2.py3-none-any.whl", hash = "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f"},
{file = "importlib_metadata-1.6.0.tar.gz", hash = "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"},
]
-importlib-resources = [
- {file = "importlib_resources-1.5.0-py2.py3-none-any.whl", hash = "sha256:85dc0b9b325ff78c8bef2e4ff42616094e16b98ebd5e3b50fe7e2f0bbcdcde49"},
- {file = "importlib_resources-1.5.0.tar.gz", hash = "sha256:6f87df66833e1942667108628ec48900e02a4ab4ad850e25fbf07cb17cf734ca"},
-]
isort = [
{file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"},
{file = "isort-4.3.21.tar.gz", hash = "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1"},
@@ -1359,9 +1225,6 @@ multidict = [
{file = "multidict-4.7.5-cp38-cp38-win_amd64.whl", hash = "sha256:544fae9261232a97102e27a926019100a9db75bec7b37feedd74b3aa82f29969"},
{file = "multidict-4.7.5.tar.gz", hash = "sha256:aee283c49601fa4c13adc64c09c978838a7e812f85377ae130a24d7198c0331e"},
]
-nodeenv = [
- {file = "nodeenv-1.3.5-py2.py3-none-any.whl", hash = "sha256:5b2438f2e42af54ca968dd1b374d14a1194848955187b0e5e4be1f73813a5212"},
-]
packaging = [
{file = "packaging-20.3-py2.py3-none-any.whl", hash = "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752"},
{file = "packaging-20.3.tar.gz", hash = "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3"},
@@ -1381,10 +1244,6 @@ pluggy = [
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
]
-pre-commit = [
- {file = "pre_commit-2.1.1-py2.py3-none-any.whl", hash = "sha256:09ebe467f43ce24377f8c2f200fe3cd2570d328eb2ce0568c8e96ce19da45fa6"},
- {file = "pre_commit-2.1.1.tar.gz", hash = "sha256:f8d555e31e2051892c7f7b3ad9f620bd2c09271d87e9eedb2ad831737d6211eb"},
-]
py = [
{file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"},
{file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"},
@@ -1521,10 +1380,6 @@ urllib3 = [
{file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"},
{file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"},
]
-virtualenv = [
- {file = "virtualenv-20.0.20-py2.py3-none-any.whl", hash = "sha256:b4c14d4d73a0c23db267095383c4276ef60e161f94fde0427f2f21a0132dde74"},
- {file = "virtualenv-20.0.20.tar.gz", hash = "sha256:fd0e54dec8ac96c1c7c87daba85f0a59a7c37fe38748e154306ca21c73244637"},
-]
wcwidth = [
{file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"},
{file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"},
diff --git a/python/pyproject.toml b/pyproject.toml
similarity index 99%
rename from python/pyproject.toml
rename to pyproject.toml
index 51f92db882d..337f67d5e8e 100644
--- a/python/pyproject.toml
+++ b/pyproject.toml
@@ -35,7 +35,6 @@ flake8-fixme = "^1.1.1"
flake8-isort = "^2.8.0"
flake8-variables-names = "^0.0.3"
isort = "^4.3.21"
-pre-commit = "^2.1.0"
pytest-cov = "^2.8.1"
pytest-mock = "^2.0.0"
pdoc3 = "^0.7.5"
diff --git a/python/pytest.ini b/pytest.ini
similarity index 100%
rename from python/pytest.ini
rename to pytest.ini
diff --git a/python/.bumpversion.cfg b/python/.bumpversion.cfg
deleted file mode 100644
index 61bb3abd6ab..00000000000
--- a/python/.bumpversion.cfg
+++ /dev/null
@@ -1,10 +0,0 @@
-[bumpversion]
-current_version = 0.5.0
-commit = False
-tag = True
-
-[bumpversion:file:pyproject.toml]
-
-[bumpversion:file:aws_lambda_powertools/__init__.py]
-search = __version__ = '{current_version}'
-replace = __version__ = '{new_version}'
diff --git a/python/.gitignore b/python/.gitignore
deleted file mode 100644
index fcab8fae4e0..00000000000
--- a/python/.gitignore
+++ /dev/null
@@ -1,298 +0,0 @@
-
-# Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode
-# Edit at https://www.gitignore.io/?templates=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 ###
-# General
-.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/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
-
-# Generated files
-.idea/**/contentModel.xml
-
-# Sensitive or high-churn files
-.idea/**/dataSources/
-.idea/**/dataSources.ids
-.idea/**/dataSources.local.xml
-.idea/**/sqlDataSources.xml
-.idea/**/dynamic.xml
-.idea/**/uiDesigner.xml
-.idea/**/dbnavigator.xml
-
-# Gradle
-.idea/**/gradle.xml
-.idea/**/libraries
-
-# Gradle and Maven with auto-import
-# When using Gradle or Maven with auto-import, you should exclude module files,
-# since they will be recreated, and may cause churn. Uncomment if using
-# auto-import.
-# .idea/modules.xml
-# .idea/*.iml
-# .idea/modules
-# *.iml
-# *.ipr
-
-# CMake
-cmake-build-*/
-
-# Mongo Explorer plugin
-.idea/**/mongoSettings.xml
-
-# File-based project format
-*.iws
-
-# IntelliJ
-out/
-
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
-atlassian-ide-plugin.xml
-
-# Cursive Clojure plugin
-.idea/replstate.xml
-
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-fabric.properties
-
-# Editor-based Rest Client
-.idea/httpRequests
-
-# Android studio 3.1+ serialized cache file
-.idea/caches/build_file_checksums.ser
-
-### 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/
-pip-wheel-metadata/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# 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/
-.nox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-.hypothesis/
-.pytest_cache/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-.python-version
-
-# pipenv
-# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-# However, in case of collaboration, if having platform-specific dependencies or dependencies
-# having no cross-platform support, pipenv may install dependencies that don't work, or not
-# install all needed dependencies.
-#Pipfile.lock
-
-# 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/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-### VisualStudioCode ###
-.vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
-!.vscode/extensions.json
-
-### VisualStudioCode Patch ###
-# Ignore all local history of files
-.history
-
-### Windows ###
-# Windows thumbnail cache files
-Thumbs.db
-Thumbs.db:encryptable
-ehthumbs.db
-ehthumbs_vista.db
-
-# Dump file
-*.stackdump
-
-# Folder config file
-[Dd]esktop.ini
-
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
-
-# Windows Installer files
-*.cab
-*.msi
-*.msix
-*.msm
-*.msp
-
-# Windows shortcuts
-*.lnk
-
-# End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode
-
-# Misc
-
-test_report
-wheelhouse
-docs
\ No newline at end of file
diff --git a/python/.pre-commit-config.yaml b/python/.pre-commit-config.yaml
deleted file mode 100644
index 1b3d03b5236..00000000000
--- a/python/.pre-commit-config.yaml
+++ /dev/null
@@ -1,40 +0,0 @@
-repos:
-- repo: local
- hooks:
- - id: isort
- name: isort
- stages: [commit]
- language: system
- entry: pipenv run isort
- types: [python]
-
- - id: black
- name: black
- stages: [commit]
- language: system
- entry: pipenv run black
- types: [python]
-
- - id: flake8
- name: flake8
- stages: [commit]
- language: system
- entry: pipenv run flake8
- types: [python]
- exclude: setup.py
-
- - id: pytest
- name: pytest
- stages: [commit]
- language: system
- entry: pipenv run pytest
- types: [python]
-
- - id: pytest-cov
- name: pytest
- stages: [push]
- language: system
- entry: pipenv run pytest --cov --cov-fail-under=70
- types: [python]
- pass_filenames: false
-
\ No newline at end of file
diff --git a/python/.vscode/settings.json b/python/.vscode/settings.json
deleted file mode 100644
index b8ab046880e..00000000000
--- a/python/.vscode/settings.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "python.pythonPath": "/Users/lessa/.pyenv/aws-lambda-powertools-_w3KY4aG-py3.7/bin/python",
- "python.formatting.provider": "black"
-}
\ No newline at end of file
diff --git a/python/CHANGELOG.md b/python/CHANGELOG.md
deleted file mode 100644
index c3d8c76207e..00000000000
--- a/python/CHANGELOG.md
+++ /dev/null
@@ -1,78 +0,0 @@
-# HISTORY
-
-## May 16th
-
-**0.9.3**
-
-* **Tracer**: Bugfix - Runtime Error for nested sync due to incorrect loop usage
-
-## May 14th
-
-**0.9.2**
-
-* **Tracer**: Bugfix - aiohttp lazy import so it's not a hard dependency
-
-## May 12th
-
-**0.9.0**
-
-* **Tracer**: Support for async functions in `Tracer` via `capture_method` decorator
-* **Tracer**: Support for `aiohttp` via `aiohttp_trace_config` trace config
-* **Tracer**: Support for patching specific modules via `patch_modules` param
-* **Tracer**: Document escape hatch mechanisms via `tracer.provider`
-
-## May 1st
-
-**0.8.1**
-
-* **Metrics**: Fix metric unit casting logic if one passes plain string (value or key)
-* **Metrics: **Fix `MetricUnit` enum values for
- - `BytesPerSecond`
- - `KilobytesPerSecond`
- - `MegabytesPerSecond`
- - `GigabytesPerSecond`
- - `TerabytesPerSecond`
- - `BitsPerSecond`
- - `KilobitsPerSecond`
- - `MegabitsPerSecond`
- - `GigabitsPerSecond`
- - `TerabitsPerSecond`
- - `CountPerSecond`
-
-## April 24th
-
-**0.8.0**
-
-* **Logger**: Introduces `Logger` class for stuctured logging as a replacement for `logger_setup`
-* **Logger**: Introduces `Logger.inject_lambda_context` decorator as a replacement for `logger_inject_lambda_context`
-* **Logger**: Raise `DeprecationWarning` exception for both `logger_setup`, `logger_inject_lambda_context`
-
-## April 20th, 2020
-
-**0.7.0**
-
-* **Middleware factory**: Introduces Middleware Factory to build your own middleware via `lambda_handler_decorator`
-* **Metrics**: Fixes metrics dimensions not being included correctly in EMF
-
-## April 9th, 2020
-
-**0.6.3**
-
-* **Logger**: Fix `log_metrics` decorator logic not calling the decorated function, and exception handling
-
-## April 8th, 2020
-
-**0.6.1**
-
-* **Metrics**: Introduces Metrics middleware to utilise CloudWatch Embedded Metric Format
-* **Metrics**: Adds deprecation warning for `log_metrics`
-
-## February 20th, 2020
-
-**0.5.0**
-
-* **Logger**: Introduces log sampling for debug - Thanks to [Danilo's contribution](https://github.com/awslabs/aws-lambda-powertools/pull/7)
-
-## November 15th, 2019
-
-* Public beta release
diff --git a/python/LICENSE b/python/LICENSE
deleted file mode 100644
index fcc7fa6828c..00000000000
--- a/python/LICENSE
+++ /dev/null
@@ -1,15 +0,0 @@
-Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
diff --git a/python/README.md b/python/README.md
deleted file mode 100644
index 42907724dba..00000000000
--- a/python/README.md
+++ /dev/null
@@ -1,435 +0,0 @@
-# Lambda Powertools
-
-    
-
-A suite of utilities for AWS Lambda Functions that makes tracing with AWS X-Ray, structured logging, and creating custom metrics asynchronously easier - Compatible with Python >=3.6.
-
-* **Status**: Release candidate
-* **How long until GA?**: [Current progress](https://github.com/awslabs/aws-lambda-powertools/projects/1)
-
-## Features
-
-**[Tracing](###Tracing)**
-
-* Capture cold start as annotation, and response and exceptions as metadata
-* Run functions locally with SAM CLI without code change to disable tracing
-* Explicitly disable tracing via env var `POWERTOOLS_TRACE_DISABLED="true"`
-* Support tracing async methods
-
-**[Logging](###Logging)**
-
-* Capture key fields from Lambda context, cold start and structures logging output as JSON
-* Log Lambda event when instructed (disabled by default)
- - Enable via `POWERTOOLS_LOGGER_LOG_EVENT="true"` or explicitly via decorator param
-* Log sampling enables DEBUG log level for a percentage of requests (disabled by default)
- - Enable via `POWERTOOLS_LOGGER_SAMPLE_RATE=0.1`, ranges from 0 to 1, where 0.1 is 10% and 1 is 100%
-* Append additional keys to structured log at any point in time
-
-**[Metrics](###Metrics)**
-
-* Aggregate up to 100 metrics using a single CloudWatch Embedded Metric Format object (large JSON blob)
-* Context manager to create an one off metric with a different dimension than metrics already aggregated
-* Validate against common metric definitions mistakes (metric unit, values, max dimensions, max metrics, etc)
-
-**[Bring your own middleware](###Bring-your-own-middleware)**
-
-* Utility to easily create your own middleware
-* Run logic before, after, and handle exceptions
-* Receive lambda handler, event, context
-* Optionally create sub-segment for each custom middleware
-
-**Environment variables** used across suite of utilities
-
-Environment variable | Description | Default | Utility
-------------------------------------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------
-POWERTOOLS_SERVICE_NAME | Sets service name used for tracing namespace, metrics dimensions and structured logging | "service_undefined" | all
-POWERTOOLS_TRACE_DISABLED | Disables tracing | "false" | [Tracing](###Tracing)
-POWERTOOLS_TRACE_MIDDLEWARES | Creates sub-segment for each middleware created by lambda_handler_decorator | "false" | [middleware_factory](###Bring-your-own-middleware)
-POWERTOOLS_LOGGER_LOG_EVENT | Logs incoming event | "false" | [Logging](###Logging)
-POWERTOOLS_LOGGER_SAMPLE_RATE | Debug log sampling | 0 | [Logging](###Logging)
-POWERTOOLS_METRICS_NAMESPACE | Metrics namespace | None | [Metrics](###Metrics)
-LOG_LEVEL | Sets logging level | "INFO" | [Logging](###Logging)
-
-## Usage
-
-See **[example](./example/README.md)** of all features, testing, and a SAM template with all Powertools env vars. All features also provide full docs, and code completion for VSCode and PyCharm.
-
-### Installation
-
-With [pip](https://pip.pypa.io/en/latest/index.html) installed, run: ``pip install aws-lambda-powertools``
-
-### Tracing
-
-#### Tracing Lambda handler and a function
-
-```python
-from aws_lambda_powertools.tracing import Tracer
-tracer = Tracer()
-# tracer = Tracer(service="payment") # can also be explicitly defined
-
-@tracer.capture_method
-def collect_payment(charge_id):
- ret = requests.post(PAYMENT_ENDPOINT) # logic
- tracer.put_annotation("PAYMENT_STATUS", "SUCCESS") # custom annotation
- return ret
-
-@tracer.capture_lambda_handler
-def handler(event, context)
- charge_id = event.get('charge_id')
- payment = collect_payment(charge_id)
- ...
-```
-
-#### Tracing asynchronous functions
-
-```python
-import asyncio
-
-from aws_lambda_powertools.tracing import Tracer
-tracer = Tracer()
-# tracer = Tracer(service="payment") # can also be explicitly defined
-
-@tracer.capture_method
-async def collect_payment(charge_id):
- ...
-
-@tracer.capture_lambda_handler
-def handler(event, context)
- charge_id = event.get('charge_id')
- payment = asyncio.run(collect_payment(charge_id)) # python 3.7+
- ...
-```
-
-#### Tracing concurrent asynchronous with gather
-
-:warning: This will no longer be necessary after [this X-Ray recorder issue is resolved](https://github.com/aws/aws-xray-sdk-python/issues/164) as it's an edge case. :warning:
-
-To safely workaround this issue, use `@tracer.capture_method` on functions not being run with `async.gather`, and instead use `in_subsegment_async` context manager escape hatch to have the same tracing effect.
-
-
-```python
-import asyncio
-
-from aws_lambda_powertools.tracing import Tracer
-tracer = Tracer()
-# tracer = Tracer(service="payment") # can also be explicitly defined
-
-async def another_async_task():
- async with tracer.provider.in_subsegment_async("## another_async_task"):
- ...
-
-async def another_async_task_2():
- async with tracer.provider.in_subsegment_async("## another_async_task_2"):
- ...
-
-@tracer.capture_method
-async def collect_payment(charge_id):
- asyncio.gather(another_async_task(), another_async_task_2())
- ...
-
-@tracer.capture_lambda_handler
-def handler(event, context)
- charge_id = event.get('charge_id')
- payment = asyncio.run(collect_payment(charge_id)) # python 3.7+
- ...
-```
-
-#### Using escape hatch mechanisms
-
-You can use `tracer.provider` attribute to access all methods provided by `xray_recorder`. This is useful when you need a feature available in X-Ray that is not available in the Tracer middleware, for example [thread-safe](https://github.com/aws/aws-xray-sdk-python/#user-content-trace-threadpoolexecutor), or [context managers](https://github.com/aws/aws-xray-sdk-python/#user-content-start-a-custom-segmentsubsegment).
-
-**Example using aiohttp with an async context manager**
-
-> NOTE: It expects you have `aiohttp` as a dependency. `aiohttp_trace_config` uses lazy import to create a trace_config object following `aiohttp` protocol.
-
-```python
-import asyncio
-import aiohttp
-
-from aws_lambda_powertools.tracing import Tracer, aiohttp_trace_config
-tracer = Tracer()
-
-# aiohttp_trace_config is x-ray extension for aiohttp trace config known as aws_xray_trace_config
-
-async def aiohttp_task():
- # Async context manager as opposed to `@tracer.capture_method`
- 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 aiohttp_task()
- ...
-
- return {
- "task": "done",
- **ret
- }
-
-@tracer.capture_lambda_handler
-def handler(event, context)
- ret = asyncio.run(async_tasks()) # python 3.7+
- ...
-```
-
-#### Using a pre-configured tracer anywhere
-
-```python
-# handler.py
-from aws_lambda_powertools.tracing import Tracer
-tracer = Tracer(service="payment")
-
-@tracer.capture_lambda_handler
-def handler(event, context)
- charge_id = event.get('charge_id')
- payment = collect_payment(charge_id)
- ...
-
-# another_file.py
-from aws_lambda_powertools.tracing import Tracer
-tracer = Tracer(auto_patch=False) # new instance using existing configuration with auto patching overriden
-```
-
-### Logging
-
-#### Structuring logs with Lambda context info
-
-```python
-from aws_lambda_powertools.logging import Logger
-
-logger = Logger()
-# Logger(service="payment", level="INFO") # also accepts explicit service name, log level
-
-@logger.inject_lambda_context
-def handler(event, context)
- logger.info("Collecting payment")
- ...
- # You can log entire objects too
- logger.info({
- "operation": "collect_payment",
- "charge_id": event['charge_id']
- })
- ...
-```
-
-
-Exerpt output in CloudWatch Logs
-
-```json
-{
- "timestamp":"2019-08-22 18:17:33,774",
- "level":"INFO",
- "location":"collect.handler:1",
- "service":"payment",
- "lambda_function_name":"test",
- "lambda_function_memory_size":"128",
- "lambda_function_arn":"arn:aws:lambda:eu-west-1:12345678910:function:test",
- "lambda_request_id":"52fdfc07-2182-154f-163f-5f0f9a621d72",
- "cold_start": "true",
- "sampling_rate": 0.1,
- "message": "Collecting payment"
-}
-
-{
- "timestamp":"2019-08-22 18:17:33,774",
- "level":"INFO",
- "location":"collect.handler:15",
- "service":"payment",
- "lambda_function_name":"test",
- "lambda_function_memory_size":"128",
- "lambda_function_arn":"arn:aws:lambda:eu-west-1:12345678910:function:test",
- "lambda_request_id":"52fdfc07-2182-154f-163f-5f0f9a621d72",
- "cold_start": "true",
- "sampling_rate": 0.1,
- "message":{
- "operation":"collect_payment",
- "charge_id": "ch_AZFlk2345C0"
- }
-}
-```
-
-
-#### Appending additional keys to current logger
-
-```python
-from aws_lambda_powertools.logging import Logger
-
-logger = Logger()
-
-@logger.inject_lambda_context
-def handler(event, context)
- if "order_id" in event:
- logger.structure_logs(append=True, order_id=event["order_id"])
- logger.info("Collecting payment")
- ...
-```
-
-
-Exerpt output in CloudWatch Logs
-
-```json
-{
- "timestamp":"2019-08-22 18:17:33,774",
- "level":"INFO",
- "location":"collect.handler:1",
- "service":"payment",
- "lambda_function_name":"test",
- "lambda_function_memory_size":"128",
- "lambda_function_arn":"arn:aws:lambda:eu-west-1:12345678910:function:test",
- "lambda_request_id":"52fdfc07-2182-154f-163f-5f0f9a621d72",
- "cold_start": "true",
- "sampling_rate": 0.1,
- "order_id": "order_id_value",
- "message": "Collecting payment"
-}
-```
-
-
-### Metrics
-
-This feature makes use of CloudWatch Embedded Metric Format (EMF), and metrics are created asynchronously by CloudWatch service.
-
-Metrics middleware validates against the minimum necessary for a metric to be published:
-
-* At least of one Metric and Dimension
-* Maximum of 9 dimensions
-* Only one Namespace
-* [Any Metric unit supported by CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html)
-
-#### Creating multiple metrics
-
-If using multiple middlewares, use `log_metrics` as the last decorator, or else it will fail with `SchemaValidationError` if no metrics are recorded.
-
-```python
-from aws_lambda_powertools.metrics import Metrics, MetricUnit
-
-metrics = Metrics()
-metrics.add_namespace(name="ServerlessAirline")
-metrics.add_metric(name="ColdStart", unit="Count", value=1)
-metrics.add_dimension(name="service", value="booking")
-
-@metrics.log_metrics
-@tracer.capture_lambda_handler
-def lambda_handler(evt, ctx):
- metrics.add_metric(name="BookingConfirmation", unit="Count", value=1)
- some_code()
- return True
-
-def some_code():
- metrics.add_metric(name="some_other_metric", unit=MetricUnit.Seconds, value=1)
- ...
-```
-
-CloudWatch EMF uses the same dimensions across all metrics. If you have metrics that should have different dimensions, use `single_metric` to create a single metric with any dimension you want. Generally, this would be an edge case since you [pay for unique metric](https://aws.amazon.com/cloudwatch/pricing/)
-
-> unique metric = (metric_name + dimension_name + dimension_value)
-
-```python
-from aws_lambda_powertools.metrics import MetricUnit, single_metric
-
-with single_metric(name="ColdStart", unit=MetricUnit.Count, value=1) as metric:
- metric.add_dimension(name="function_context", value="$LATEST")
-```
-
-> **NOTE**: When using Metrics() in multiple places in your code, make sure to use `POWERTOOLS_METRICS_NAMESPACE` env var, or setting namespace param.
-
-### Bring your own middleware
-
-This feature allows you to create your own middleware as a decorator with ease by following a simple signature.
-
-* Accept 3 mandatory args - `handler, event, context`
-* Always return the handler with event/context or response if executed
- - Supports nested middleware/decorators use case
-
-#### Middleware with no params
-
-```python
-from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
-
-@lambda_handler_decorator
-def middleware_name(handler, event, context):
- return handler(event, context)
-
-@lambda_handler_decorator
-def middleware_before_after(handler, event, context):
- logic_before_handler_execution()
- response = handler(event, context)
- logic_after_handler_execution()
- return response
-
-
-# middleware_name will wrap Lambda handler
-# and simply return the handler as we're not pre/post-processing anything
-# then middleware_before_after will wrap middleware_name
-# run some code before/after calling the handler returned by middleware_name
-# This way, lambda_handler is only actually called once (top-down)
-@middleware_before_after # This will run last
-@middleware_name # This will run first
-def lambda_handler(event, context):
- return True
-```
-
-#### Middleware with params
-
-```python
-@lambda_handler_decorator
-def obfuscate_sensitive_data(handler, event, context, fields=None):
- # Obfuscate email before calling Lambda handler
- if fields:
- for field in fields:
- field = event.get(field, "")
- event[field] = obfuscate_pii(field)
-
- return handler(event, context)
-
-@obfuscate_sensitive_data(fields=["email"])
-def lambda_handler(event, context):
- return True
-```
-
-#### Tracing middleware execution
-
-This makes use of an existing Tracer instance that you may have initialized anywhere in your code. If no Tracer instance is found, it'll initialize one using default options.
-
-```python
-from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
-
-@lambda_handler_decorator(trace_execution=True)
-def middleware_name(handler, event, context):
- return handler(event, context)
-
-@middleware_name
-def lambda_handler(event, context):
- return True
-```
-
-Optionally, you can enrich the final trace with additional annotations and metadata by retrieving a copy of the Tracer used.
-
-```python
-from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
-from aws_lambda_powertools.tracing import Tracer
-
-@lambda_handler_decorator(trace_execution=True)
-def middleware_name(handler, event, context):
- tracer = Tracer() # Takes a copy of an existing tracer instance
- tracer.add_anotation...
- tracer.metadata...
- return handler(event, context)
-
-@middleware_name
-def lambda_handler(event, context):
- return True
-```
-
-### Debug mode
-
-By default, all log statements from AWS Lambda Powertools package are suppressed. If you'd like to enable them, use `set_package_logger` utility:
-
-```python
-import aws_lambda_powertools
-aws_lambda_powertools.logging.logger.set_package_logger()
-...
-```
diff --git a/python/tests/functional/__init__.py b/tests/functional/__init__.py
similarity index 100%
rename from python/tests/functional/__init__.py
rename to tests/functional/__init__.py
diff --git a/python/tests/functional/test_aws_lambda_logging.py b/tests/functional/test_aws_lambda_logging.py
similarity index 100%
rename from python/tests/functional/test_aws_lambda_logging.py
rename to tests/functional/test_aws_lambda_logging.py
diff --git a/python/tests/functional/test_logger.py b/tests/functional/test_logger.py
similarity index 100%
rename from python/tests/functional/test_logger.py
rename to tests/functional/test_logger.py
diff --git a/python/tests/functional/test_metrics.py b/tests/functional/test_metrics.py
similarity index 100%
rename from python/tests/functional/test_metrics.py
rename to tests/functional/test_metrics.py
diff --git a/python/tests/functional/test_middleware_factory.py b/tests/functional/test_middleware_factory.py
similarity index 100%
rename from python/tests/functional/test_middleware_factory.py
rename to tests/functional/test_middleware_factory.py
diff --git a/python/tests/functional/test_tracing.py b/tests/functional/test_tracing.py
similarity index 100%
rename from python/tests/functional/test_tracing.py
rename to tests/functional/test_tracing.py
diff --git a/python/tests/unit/__init__.py b/tests/unit/__init__.py
similarity index 100%
rename from python/tests/unit/__init__.py
rename to tests/unit/__init__.py
diff --git a/python/tests/unit/test_tracing.py b/tests/unit/test_tracing.py
similarity index 100%
rename from python/tests/unit/test_tracing.py
rename to tests/unit/test_tracing.py