lambdex
Advanced tools
| import hashlib | ||
| import requests | ||
| def handler(event, context): | ||
| url = event["url"] | ||
| print("%s sha256:%s" % (url, hashlib.sha256(requests.get(url).content).hexdigest())) | ||
| def other_handler(event, context): | ||
| print("Other handler invoked") |
| #!/bin/bash | ||
| pex -r requirements.txt -o lambda_function.zip | ||
| lambdex build -s example_function.py lambda_function.zip | ||
| lambdex test lambda_function.zip <(echo '{"url": "https://github.com/pantsbuild"}') |
| requests |
| import hashlib | ||
| import flask | ||
| import requests | ||
| def handler(request): | ||
| request_json = request.get_json() | ||
| url = request_json.get("url") | ||
| if not url: | ||
| print("No URL provided!") | ||
| return {} | ||
| print("%s sha256:%s" % (url, hashlib.sha256(requests.get(url).content).hexdigest())) | ||
| return { | ||
| "url": flask.escape(url), | ||
| "sha256": hashlib.sha256(requests.get(url).content).hexdigest(), | ||
| } |
| #!/bin/bash | ||
| pex -r requirements.txt -o lambda_function.zip | ||
| dist/lambdex build -s example_http_function.py -M main.py lambda_function.zip | ||
| dist/lambdex test --type gcp-http lambda_function.zip <(echo '{"url": "https://github.com/pantsbuild"}') |
| flask<2 | ||
| requests |
+8
-0
| # Release Notes | ||
| ## 0.1.6 | ||
| This release brings support for creating a lambdex that works on GCP. The feature should work for | ||
| ancient Pex but is only tested against modern Pex (>=1.6). | ||
| * Allow arbitrary handlers to support more runtimes. (#22) | ||
| * Create arg that can specify module name. (#21) | ||
| ## 0.1.5 | ||
@@ -4,0 +12,0 @@ |
@@ -26,3 +26,6 @@ # Copyright 2021 Pants project contributors (see CONTRIBUTORS.md). | ||
| EVENT_FUNCTION_SIGNATURE = "event" | ||
| GCP_HTTP_FUNCTION_SIGNATURE = "gcp-http" | ||
| def die(msg): | ||
@@ -78,3 +81,3 @@ print(msg, file=sys.stderr) | ||
| _write_zip_content( | ||
| zf, "lambdex_handler.py", pkgutil.get_data("lambdex.resources", "lambdex_handler.py") | ||
| zf, options.module, pkgutil.get_data("lambdex.resources", "lambdex_handler.py") | ||
| ) | ||
@@ -85,2 +88,3 @@ | ||
| # [-H handler] | ||
| # [-M module.py] | ||
| # [-s script.py] | ||
@@ -131,3 +135,12 @@ # [-e pkg:symbol] | ||
| parser.add_argument( | ||
| "-M", | ||
| "--script-module", | ||
| dest="module", | ||
| default="lambdex_handler.py", | ||
| metavar="FILENAME", | ||
| help="Root module of the lambda.", | ||
| ) | ||
| def load_json_blob(filename): | ||
@@ -199,9 +212,21 @@ if filename == "-": | ||
| runner = EntryPoint.parse("run = %s" % lambdex_entry_point).resolve() | ||
| if args.empty: | ||
| runner({}, None) | ||
| else: | ||
| for filename in args.files: | ||
| runner(load_json_blob(filename), None) | ||
| if args.type == EVENT_FUNCTION_SIGNATURE: | ||
| if args.empty: | ||
| runner({}, None) | ||
| else: | ||
| for filename in args.files: | ||
| runner(load_json_blob(filename), None) | ||
| elif args.type == GCP_HTTP_FUNCTION_SIGNATURE: | ||
| import flask | ||
| app = flask.Flask("test-app") | ||
| if args.empty: | ||
| with app.test_request_context(json={}): | ||
| runner(flask.request) | ||
| else: | ||
| for filename in args.files: | ||
| with app.test_request_context(json=load_json_blob(filename)): | ||
| runner(flask.request) | ||
| def configure_test_command(parser): | ||
@@ -242,3 +267,11 @@ parser = parser.add_parser( | ||
| parser.add_argument( | ||
| "--type", | ||
| dest="type", | ||
| default=EVENT_FUNCTION_SIGNATURE, | ||
| choices=[EVENT_FUNCTION_SIGNATURE, GCP_HTTP_FUNCTION_SIGNATURE], | ||
| help="The type of function to be tested.", | ||
| ) | ||
| def configure_clp(): | ||
@@ -245,0 +278,0 @@ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
@@ -57,3 +57,3 @@ # Copyright 2021 Pants project contributors (see CONTRIBUTORS.md). | ||
| def handler(event, context): | ||
| return __RUNNER(event, context) | ||
| def handler(*args, **kwargs): | ||
| return __RUNNER(*args, **kwargs) |
| # Copyright 2021 Pants project contributors (see CONTRIBUTORS.md). | ||
| # Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
| __version__ = "0.1.5" | ||
| __version__ = "0.1.6" |
+125
-2
@@ -1,4 +0,4 @@ | ||
| Metadata-Version: 1.1 | ||
| Metadata-Version: 2.1 | ||
| Name: lambdex | ||
| Version: 0.1.5 | ||
| Version: 0.1.6 | ||
| Summary: Lambdex turns pex files into aws lambda python functions. | ||
@@ -8,1 +8,124 @@ Home-page: https://github.com/pantsbuild/lambdex | ||
| Author-email: pantsbuild@gmail.com | ||
| Requires-Python: >=2.7,<3.10,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.* | ||
| Description-Content-Type: text/markdown | ||
| Classifier: Development Status :: 4 - Beta | ||
| Classifier: Intended Audience :: Developers | ||
| Classifier: License :: OSI Approved :: Apache Software License | ||
| Classifier: Operating System :: Unix | ||
| Classifier: Operating System :: POSIX :: Linux | ||
| Classifier: Operating System :: MacOS :: MacOS X | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 2 | ||
| Classifier: Programming Language :: Python :: 2.7 | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Programming Language :: Python :: 3.6 | ||
| Classifier: Programming Language :: Python :: 3.7 | ||
| Classifier: Programming Language :: Python :: 3.8 | ||
| Classifier: Programming Language :: Python :: 3.9 | ||
| Classifier: Topic :: Software Development :: Build Tools | ||
| Classifier: Topic :: System :: Archiving :: Packaging | ||
| Classifier: Topic :: System :: Software Distribution | ||
| Classifier: Topic :: Utilities | ||
| Requires-Dist: pex>=1.1.15 | ||
| Requires-Dist: flask<2 ; extra == "test-gcp-http" and ( python_version < '3.6') | ||
| Requires-Dist: flask~=2.0.0 ; extra == "test-gcp-http" and ( python_version >= '3.6') | ||
| Project-URL: Changelog, https://github.com/pantsbuild/lambdex/blob/main/CHANGES.md | ||
| Provides-Extra: test-gcp-http | ||
| # lambdex | ||
| lambdex turns pex files into aws lambda functions. | ||
| [pex](https://github.com/pantsbuild/pex) is a tool that simplifies packaging python environments and is ideally suited | ||
| for aws lambda. lambdex takes pex files and turns them into aws lambda functions, allowing | ||
| you to more easily run complex applications in the cloud. | ||
| aws lambda documentation and concepts can be found [here](https://aws.amazon.com/lambda/getting-started/). | ||
| ## using the lambdex cli | ||
| The lambdex cli has two subcommands: `build` and `test`. `build` further has two possible modes of operation: by specifying | ||
| an entry point that already exists within the pex file (`-e`) or by specifying an external script and handler to embed within | ||
| the pex file (`-s/-H`). | ||
| ### step 1: package a pex file | ||
| First you must package a pex file. Assuming you already have the `pex` tool | ||
| and a requirements.txt, you can simply run | ||
| pex -r requirements.txt -o lambda_function.pex | ||
| to produce a pex file containing the requirements. If you must build a pex | ||
| file with platform-specific extensions, see the tips section below for more | ||
| information about building Amazon Linux-specific extensions. | ||
| ### step 2: add lambdex handler | ||
| This can be done one of two ways, depending on where your code lives. | ||
| If you have a handler function named 'handler' in package | ||
| 'mymodule.myapp' that is already contained within lambda_function.pex, | ||
| then you can simply run | ||
| lambdex build -e mymodule.myapp:handler lambda_function.pex | ||
| If you have a script function.py with a lambda handler named `my_handler`, you would instead run | ||
| lambdex build -s function.py -H my_handler lambda_function.pex | ||
| This bundles function.py within the pex environment and instructs lambdex to | ||
| call the python function `my_handler` when being invoked by AWS. | ||
| If you would like to build a GCP Cloud Function, you will need to specify the name of the entrypoint module | ||
| to be `main.py`. | ||
| lambdex build -s example_http_function.py -M main.py lambda_function.zip | ||
| ### step 3 (optional): test your lambdex function | ||
| Once you have created a lambdex file, you can test it as if it were being invoked by Amazon using `lambdex test`. | ||
| Given a lambdex package `lambda_function.pex`, you can either send it an empty json event using | ||
| lambdex test --empty lambda_function.pex | ||
| You can alternately supply a list of files containing json structs e.g. | ||
| lambdex test lambda_function.pex event1.json event2.json ... | ||
| Testing a GCP HTTP Cloud Function requires specifying the type. | ||
| lambdex test --type gcp-http lambda_function.zip | ||
| > Note: In order to test GCP HTTP Cloud Functions, you must be using pex v1.6 or greater. | ||
| ### step 4: upload lambda function | ||
| You can create/update lambda functions via the AWS Console, or you can do it | ||
| via the CLI using `aws lambda create-function` or `aws lambda update-function-code` respectively. | ||
| *NOTE*: When creating the function, you must specify the AWS Lambda handler as | ||
| `lambdex_handler.handler`. Via the CLI, this is the `--handler` flag. This | ||
| is the wrapper injected by lambdex that manages invocation of your code. | ||
| Do not confuse this with the `-H` option to `lambdex build`. | ||
| ## tips | ||
| ### building amazon linux pex files | ||
| Most simple dependencies have no platform-specific extensions and thus can be built anywhere. However there are a number of | ||
| popular packages (e.g. numpy, scipy, matplotlib, PIL, ...) that require building C extensions that can prove tricky | ||
| to get packaged correctly. | ||
| Amazon provides an amazonlinux docker image which can be useful for building platform-specific extensions to run | ||
| on AWS Lambda. See [documentation](http://docs.aws.amazon.com/AmazonECR/latest/userguide/amazon_linux_container_image.html) | ||
| for information about that image. | ||
| The minimum Dockerfile to produce can environment that can build Amazon Linux-specific pex files can be found [here](https://github.com/pantsbuild/lambdex/blob/main/Dockerfile) | ||
| ### controlling runtime execution | ||
| To override the entry point that was specified at build time, you can use the `LAMBDEX_ENTRY_POINT` env var: | ||
| LAMBDEX_ENTRY_POINT=mymodule.myapp:other_handler ... | ||
+6
-0
@@ -34,2 +34,8 @@ [build-system] | ||
| [tool.flit.metadata.requires-extra] | ||
| test-gcp-http = [ | ||
| "flask<2; python_version < '3.6'", | ||
| "flask~=2.0.0; python_version >= '3.6'" | ||
| ] | ||
| [tool.flit.scripts] | ||
@@ -36,0 +42,0 @@ lambdex = "lambdex.bin.lambdex:main" |
+11
-0
@@ -45,2 +45,7 @@ # lambdex | ||
| If you would like to build a GCP Cloud Function, you will need to specify the name of the entrypoint module | ||
| to be `main.py`. | ||
| lambdex build -s example_http_function.py -M main.py lambda_function.zip | ||
| ### step 3 (optional): test your lambdex function | ||
@@ -57,2 +62,8 @@ | ||
| Testing a GCP HTTP Cloud Function requires specifying the type. | ||
| lambdex test --type gcp-http lambda_function.zip | ||
| > Note: In order to test GCP HTTP Cloud Functions, you must be using pex v1.6 or greater. | ||
| ### step 4: upload lambda function | ||
@@ -59,0 +70,0 @@ |
+6
-1
@@ -15,2 +15,6 @@ #!/usr/bin/env python | ||
| extras_require = \ | ||
| {"test-gcp-http:python_version < '3.6'": ['flask<2'], | ||
| "test-gcp-http:python_version >= '3.6'": ['flask~=2.0.0']} | ||
| entry_points = \ | ||
@@ -20,3 +24,3 @@ {'console_scripts': ['lambdex = lambdex.bin.lambdex:main']} | ||
| setup(name='lambdex', | ||
| version='0.1.5', | ||
| version='0.1.6', | ||
| description='Lambdex turns pex files into aws lambda python functions.', | ||
@@ -29,4 +33,5 @@ author='The Lambdex developers', | ||
| install_requires=install_requires, | ||
| extras_require=extras_require, | ||
| entry_points=entry_points, | ||
| python_requires='>=2.7,<3.10,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*', | ||
| ) |
+26
-6
@@ -21,20 +21,40 @@ [tox] | ||
| commands = | ||
| pex -r {toxinidir}/examples/requirements.txt -o {toxinidir}/dist/lambda_function.pex | ||
| tox -e pex | ||
| {toxinidir}/dist/lambdex build -s examples/example_function.py -H handler {toxinidir}/dist/lambda_function.pex | ||
| [_event_integration] | ||
| deps = | ||
| {[_integration]deps} | ||
| commands = | ||
| {[_integration]commands} | ||
| pex -r {toxinidir}/examples/event_based/requirements.txt -o {toxinidir}/dist/lambda_function.pex | ||
| {toxinidir}/dist/lambdex build -s examples/event_based/example_function.py -H handler -M lambdex_handler.py {toxinidir}/dist/lambda_function.pex | ||
| {toxinidir}/dist/lambda_function.pex -c 'from lambdex_handler import handler; handler(\{"url":"https://github.com/pantsbuild/lambdex"\}, None)' | ||
| tox -e entry-point-env-var | ||
| [_gcp_http_integration] | ||
| deps = | ||
| {[_integration]deps} | ||
| .[test-gcp-http] | ||
| commands = | ||
| {[_integration]commands} | ||
| pex -r {toxinidir}/examples/gcp_http/requirements.txt -o {toxinidir}/dist/gcp_http_function.pex | ||
| {toxinidir}/dist/lambdex build -s examples/gcp_http/example_http_function.py -H handler -M main.py {toxinidir}/dist/gcp_http_function.pex | ||
| {toxinidir}/dist/lambdex test --type gcp-http --empty {toxinidir}/dist/gcp_http_function.pex | ||
| [testenv:py{27,36,37,38,39}-int-pre-pex1.6] | ||
| # NB: 1.4.8 is the first pre-1.6.0 version to support -c. | ||
| deps = | ||
| {[_integration]deps} | ||
| {[_event_integration]deps} | ||
| pex==1.4.8 | ||
| commands = {[_integration]commands} | ||
| commands = | ||
| {[_event_integration]commands} | ||
| [testenv:py{27,36,37,38,39}-int-post-pex1.6] | ||
| deps = | ||
| {[_integration]deps} | ||
| {[_event_integration]deps} | ||
| {[_gcp_http_integration]deps} | ||
| pex>=1.6.0 | ||
| commands = {[_integration]commands} | ||
| commands = | ||
| {[_event_integration]commands} | ||
| {[_gcp_http_integration]commands} | ||
@@ -41,0 +61,0 @@ [testenv:entry-point-env-var] |
| import hashlib | ||
| import requests | ||
| def handler(event, context): | ||
| url = event["url"] | ||
| print("%s sha256:%s" % (url, hashlib.sha256(requests.get(url).content).hexdigest())) | ||
| def other_handler(event, context): | ||
| print("Other handler invoked") |
| #!/bin/bash | ||
| pex -r requirements.txt -o lambda_function.zip | ||
| lambdex build -s example_function.py lambda_function.zip | ||
| lambdex test lambda_function.zip <(echo '{"url": "https://github.com/pantsbuild"}') |
| requests |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
45320
24.32%26
13.04%339
16.1%