Unverified Commit 3fb90968 authored by Burak's avatar Burak Committed by GitHub
Browse files

Python: Allow injecting Lambda Context (#1985)



* Provide Python wrappers for Lambda related types

* Introduce `PyContext` to wrap raw context object

* Use new `PyContext` in handlers

* Expose `lambda` module to Python

* Use `LambdaContext` in example service

* Start Lambda handler in a different thread

* Print summary of Lambda context in Pokemon service

* Make sure to include Python `builtins` in tests

* Make `lambda_ctx` optional

Co-authored-by: default avatarMatteo Bigoi <1781140+crisidev@users.noreply.github.com>

* Only inject types if they are type-hinted as `Optional[T]`

* Export Lambda module as `aws_lambda` instead of `lambda_`

* Comment why we need to run Hyper server in a background thread

* Move `is_optional_of` to `util` module

* Use `HeaderMap::from_iter` to build headers

* Support edge case of `(None, T)` in `util::is_optional_of`

* Make Lambda related types feature gated

* Remove feature gate for Lambda

* Make `xray_trace_id` an `Option`

* Remove `aws-lambda` feature from generated `Cargo.toml`s

* Fix linting issues

* Pin `lambda_runtime` to `0.7.1`

* Remove duplicate dependency in `Cargo.toml`

Co-authored-by: default avatarMatteo Bigoi <1781140+crisidev@users.noreply.github.com>
parent 9d2d0880
Loading
Loading
Loading
Loading
+0 −18
Original line number Diff line number Diff line
@@ -7,7 +7,6 @@ package software.amazon.smithy.rust.codegen.server.python.smithy.customizations

import software.amazon.smithy.model.neighbor.Walker
import software.amazon.smithy.rust.codegen.client.smithy.customize.RustCodegenDecorator
import software.amazon.smithy.rust.codegen.core.rustlang.Feature
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
import software.amazon.smithy.rust.codegen.core.rustlang.docs
import software.amazon.smithy.rust.codegen.core.rustlang.rust
@@ -104,21 +103,6 @@ class PubUsePythonTypesDecorator : RustCodegenDecorator<ServerProtocolGenerator,
        clazz.isAssignableFrom(ServerCodegenContext::class.java)
}

/**
 * Decorator adding an `aws-lambda` feature to the generated crate.
 */
class PythonFeatureFlagsDecorator : RustCodegenDecorator<ServerProtocolGenerator, ServerCodegenContext> {
    override val name: String = "PythonFeatureFlagsDecorator"
    override val order: Byte = 0

    override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) {
        rustCrate.mergeFeature(Feature("aws-lambda", true, listOf("aws-smithy-http-server-python/aws-lambda")))
    }

    override fun supportsCodegenContext(clazz: Class<out CodegenContext>): Boolean =
        clazz.isAssignableFrom(ServerCodegenContext::class.java)
}

val DECORATORS = listOf(
    /**
     * Add the [InternalServerError] error to all operations.
@@ -131,6 +115,4 @@ val DECORATORS = listOf(
    PubUsePythonTypesDecorator(),
    // Render the Python shared library export.
    PythonExportModuleDecorator(),
    // Add the `aws-lambda` feature flag
    PythonFeatureFlagsDecorator(),
)
+17 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ class PythonServerModuleGenerator(
                renderPyLogging()
                renderPyMiddlewareTypes()
                renderPyTlsTypes()
                renderPyLambdaTypes()
                renderPyApplicationType()
            }
        }
@@ -179,6 +180,22 @@ class PythonServerModuleGenerator(
        )
    }

    private fun RustWriter.renderPyLambdaTypes() {
        rustTemplate(
            """
            let aws_lambda = #{pyo3}::types::PyModule::new(py, "aws_lambda")?;
            aws_lambda.add_class::<#{SmithyPython}::lambda::PyLambdaContext>()?;
            pyo3::py_run!(
                py,
                aws_lambda,
                "import sys; sys.modules['$libName.aws_lambda'] = aws_lambda"
            );
            m.add_submodule(aws_lambda)?;
            """,
            *codegenScope,
        )
    }

    // Render Python application type.
    private fun RustWriter.renderPyApplicationType() {
        rustTemplate(
+3 −3
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ class PythonServerOperationHandlerGenerator(
                /// Python handler for operation `$operationName`.
                pub(crate) async fn $fnName(
                    input: $input,
                    state: #{SmithyServer}::Extension<#{pyo3}::PyObject>,
                    state: #{SmithyServer}::Extension<#{SmithyPython}::context::PyContext>,
                    handler: #{SmithyPython}::PyHandler,
                ) -> std::result::Result<$output, $error> {
                    // Async block used to run the handler and catch any Python error.
@@ -95,7 +95,7 @@ class PythonServerOperationHandlerGenerator(
                    let output = if handler.args == 1 {
                        pyhandler.call1((input,))?
                    } else {
                        pyhandler.call1((input, state.0))?
                        pyhandler.call1((input, #{pyo3}::ToPyObject::to_object(&state.0, py)))?
                    };
                    output.extract::<$output>()
                })
@@ -114,7 +114,7 @@ class PythonServerOperationHandlerGenerator(
                    let coroutine = if handler.args == 1 {
                        pyhandler.call1((input,))?
                    } else {
                        pyhandler.call1((input, state.0))?
                        pyhandler.call1((input, #{pyo3}::ToPyObject::to_object(&state.0, py)))?
                    };
                    #{pyo3_asyncio}::tokio::into_future(coroutine)
                })?;
+7 −5
Original line number Diff line number Diff line
@@ -12,12 +12,9 @@ Python server runtime for Smithy Rust Server Framework.
"""
publish = true

[features]
aws-lambda = ["aws-smithy-http-server/aws-lambda", "dep:lambda_http"]

[dependencies]
aws-smithy-http = { path = "../aws-smithy-http" }
aws-smithy-http-server = { path = "../aws-smithy-http-server" }
aws-smithy-http-server = { path = "../aws-smithy-http-server", features = ["aws-lambda"] }
aws-smithy-json = { path = "../aws-smithy-json" }
aws-smithy-types = { path = "../aws-smithy-types" }
aws-smithy-xml = { path = "../aws-smithy-xml" }
@@ -25,10 +22,15 @@ bytes = "1.2"
futures = "0.3"
http = "0.2"
hyper = { version = "0.14.20", features = ["server", "http1", "http2", "tcp", "stream"] }
lambda_http = { version = "0.7.1", optional = true }
tls-listener = { version = "0.5.1", features = ["rustls", "hyper-h2"] }
rustls-pemfile = "1.0.1"
tokio-rustls = "0.23.4"
lambda_http = { version = "0.7.1" }
# There is a breaking change in `lambda_runtime` between `0.7.0` and `0.7.1`,
# and `lambda_http` depends on `0.7` which by default resolves to `0.7.1` but in our CI
# we are running `minimal-versions` which downgrades `lambda_runtime` to `0.7.0` and fails to compile
# because of the breaking change. Here we are forcing it to use `lambda_runtime = 0.7.1`.
lambda_runtime = { version = "0.7.1" }
num_cpus = "1.13.1"
parking_lot = "0.12.1"
pin-project-lite = "0.2"
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ release: codegen
	ln -sf $(RELEASE_SHARED_LIBRARY_SRC) $(SHARED_LIBRARY_DST)

run: build
	python $(CUR_DIR)/pokemon_service.py
	python3 $(CUR_DIR)/pokemon_service.py

test: build
	cargo test
Loading